소스 코드를 읽을 때의 문제점 중 하나는 백본을 바로잡지 못하는 딜레마에 빠지게 된다는 것입니다. 이 기사 시리즈는 React 프레임워크(JSX/virtual DOM/Components/.. .) (x)react를 구현하는 동안
이전 글에서 JSX와 Virtual DOM을 인터페이스에 렌더링하는 과정을 설명하고 해당 코드를 구현했습니다.
import React from 'react' import ReactDOM from 'react-dom' const element = ( <p> hello<span>world!</span> </p> ) ReactDOM.render( element, document.getElementById('root') )
이 섹션에서는 구성 요소가 인터페이스 프로세스에 렌더링되는 방법을 계속해서 살펴보겠습니다. 여기서는 컴포넌트의 개념을 소개합니다. 컴포넌트는 본질적으로 함수입니다
. 다음은 표준 컴포넌트 코드입니다: 组件本质上就是一个函数
,如下就是一段标准组件代码:
import React from 'react' // 写法 1: class A { render() { return <p>I'm componentA</p> } } // 写法 2:无状态组件 const A = () => <p>I'm componentA</p> ReactDOM.render(<a></a>, document.body)
<a name="componentA"></a>
是 JSX 的写法,和上一篇同理,babel 将其转化为 React.createElement() 的形式,转化结果如下所示:
React.createElement(A, null)
可以看到当 JSX 中是自定义组件的时候,createElement 后接的第一个参数变为了函数,在 repl 打印 <a name="componentA"></a>
,结果如下:
{ attributes: undefined, children: [], key: undefined, nodeName: ƒ A() }
注意这时返回的 Virtual DOM 中的 nodeName 也变为了函数。根据这些线索,我们对之前的 render
函数进行改造。
function render(vdom, container) { if (_.isFunction(vdom.nodeName)) { // 如果 JSX 中是自定义组件 let component, returnVdom if (vdom.nodeName.prototype.render) { component = new vdom.nodeName() returnVdom = component.render() } else { returnVdom = vdom.nodeName() // 针对无状态组件:const A = () => <p>I'm componentsA</p> } render(returnVdom, container) return } }
至此,我们完成了对组件的处理逻辑。
在上个小节组件 A 中,是没有引入任何属性和状态的,我们希望组件间能进行属性的传递(props)以及组件内能进行状态的记录(state)。
import React, { Component } from 'react' class A extends Component { render() { return <p>I'm {this.props.name}</p> } } ReactDOM.render(<a></a>, document.body)
在上面这段代码中,看到 A 函数继承自 Component。我们来构造这个父类 Component,并在其添加 state、props、setState 等属性方法,从而让子类继承到它们。
function Component(props) { this.props = props this.state = this.state || {} }
首先,我们将组件外的 props 传进组件内,修改 render 函数中以下代码:
function render(vdom, container) { if (_.isFunction(vdom.nodeName)) { let component, returnVdom if (vdom.nodeName.prototype.render) { component = new vdom.nodeName(vdom.attributes) // 将组件外的 props 传进组件内 returnVdom = component.render() } else { returnVdom = vdom.nodeName(vdom.attributes) // 处理无状态组件:const A = (props) => <p>I'm {props.name}</p> } ... } ... }
实现完组件间 props 的传递后,再来聊聊 state,在 react 中是通过 setState 来完成组件状态的改变的,后续章节会对这个 api(异步)深入探究,这里简单实现如下:
function Component(props) { this.props = props this.state = this.state || {} } Component.prototype.setState = function() { this.state = Object.assign({}, this.state, updateObj) // 这里简单实现,后续篇章会深入探究 const returnVdom = this.render() // 重新渲染 document.getElementById('root').innerHTML = null render(returnVdom, document.getElementById('root')) }
此时虽然已经实现了 setState 的功能,但是 document.getElementById('root')
Component.prototype.setState = function(updateObj) { this.state = Object.assign({}, this.state, updateObj) _render(this) // 重新渲染 }
<a name="comComponentA"></a>
JSX로 작성했는데, 이전 글과 마찬가지로 babel을 React.createElement() 형태로 변환해 보면 다음과 같습니다.
function render(vdom, container) { let component if (_.isFunction(vdom.nodeName)) { if (vdom.nodeName.prototype.render) { component = new vdom.nodeName(vdom.attributes) } else { component = vdom.nodeName(vdom.attributes) // 处理无状态组件:const A = (props) => <p>I'm {props.name}</p> } } component ? _render(component, container) : _render(vdom, container) }
<a name="comComponentA"></a>
를 인쇄하면 결과는 다음과 같습니다.
function _render(component, container) { const vdom = component.render ? component.render() : component if (_.isString(vdom) || _.isNumber(vdom)) { container.innerText = container.innerText + vdom return } const dom = document.createElement(vdom.nodeName) for (let attr in vdom.attributes) { setAttribute(dom, attr, vdom.attributes[attr]) } vdom.children.forEach(vdomChild => render(vdomChild, dom)) if (component.container) { // 注意:调用 setState 方法时是进入这段逻辑,从而实现我们将 dom 的逻辑与 setState 函数分离的目标;知识点: new 出来的同一个实例 component.container.innerHTML = null component.container.appendChild(dom) return } component.container = container container.appendChild(dom) }
render
기능을 변형했습니다.
class A extends Component { constructor(props) { super(props) this.state = { count: 1 } } click() { this.setState({ count: ++this.state.count }) } render() { return ( <p> <button>Click Me!</button> </p><p>{this.props.name}:{this.state.count}</p> ) } } ReactDOM.render( <a></a>, document.getElementById('root') )
이전 섹션의 컴포넌트 A에는 속성과 상태가 도입되지 않았습니다. 컴포넌트(props) 간에 속성을 전달할 수 있고 컴포넌트(state) 내에 상태를 기록할 수 있기를 바랍니다.
rrreee위 코드에서 A 함수는 Component에서 상속되는 것을 볼 수 있습니다. 이 상위 클래스 Component를 구성하고 여기에 state, props, setState 및 기타 속성 메서드를 추가하여 하위 클래스가 상속할 수 있도록 하겠습니다.
rrreee컴포넌트 간 props 전송이 완료된 후, 반응에서는 setState를 사용합니다. 구성 요소 상태를 완료합니다. 다음 장에서는 이 API(비동기)를 자세히 살펴보겠습니다. 여기서 간단한 구현은 다음과 같습니다.
rrreee setState 함수가 현재 구현되었지만 document.getElementById('root' )
이는 분명히 우리가 setState에 노드를 작성하려는 것이 아닙니다. _render 함수와 관련된 dom 노드를 전송합니다.
당연히 이와 관련된 렌더 함수를 재구성합니다.
rrreee에서 _render를 분리합니다. render 함수 이 함수의 목적은 _render 논리가 setState 함수에서 호출되도록 허용하는 것입니다. 완전한 _render 함수는 다음과 같습니다:
rrreee다음 사용 사례를 사용하여 작성된 반응을 실행해 보겠습니다! rrreee렌더링은 다음과 같습니다.
🎜Summary🎜🎜Components는 함수입니다. JSX가 사용자 정의 구성 요소인 경우 babel 변환 후 React.createElement(fn, ..)의 첫 번째 매개 변수는 함수가 됩니다. 🎜🎜또한 state/props/setState와 같은 API를 상위 클래스 React.Component에 캡슐화하여 이러한 속성과 메서드를 하위 클래스에서 호출할 수 있습니다. 🎜🎜위 내용은 이 글의 전체 내용입니다. 모든 분들의 학습에 도움이 되었으면 좋겠습니다. 더 많은 관련 내용은 PHP 중국어 홈페이지를 주목해주세요! 🎜🎜관련 권장 사항: 🎜🎜🎜vue의 config/index.js에 대한 자세한 설명: 구성🎜🎜🎜🎜Angular 템플릿 구문 설명🎜🎜🎜위 내용은 React 구성요소 및 상태|소품 구문 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!