const div = React.createElement('div', null)
是一个元素
const Div = () => React.createElement('div', null)
是一个组件(就是一个回调),首字母大写
在 React 中,HTML
等标签会被翻译成 React.creatElement(‘div’)函数组件
function Hello(props) {
return <h1> Hi, {props.name} </h1>
}
// 使用 <Hello name="Dudu" />
类组件
class Hello extends React.Component {
constructor() {
super()
this.state = {n: 0}
}
render() {
return <h1> Hi, {this.props.name} </h1>
}
}
// 使用 <Hello name="Dudu" />
内部数据 state
类组件:用 this.state.n 读,用 this.setState({n: this.state.n+1}) 写(异步更新 )
函数组件:[n, setN] = useState(0),n 为数据,setN 为设置函数,0 为 n 的初始值
import React from 'react';
import ReactDOM from 'react-dom';
import './style.css';
function App() {
return (
<div className='father'>
father
<Son />
</div>
);
}
class Son extends React.Component {
constructor() {
super();
this.state = { n: 0 };
}
add() {
// 不能直接 this.state.n += 1,react 不监听数据
// this.setState({ n: this.state.n + 1 }); // 产生一个新对象
// 由于 this.setState 为异步更新,若要实实时打印n,一般使用函数
this.setSate((state) => {
const n = state.n + 1;
console.log(n);
return {n};
})
}
render() {
return (
<div className='son'>
Son n: {this.state.n}
<button onClick={() => {
this.add()
}}> +1 </button>
<Grandson />
</div>
);
}
}
const Grandson = () => {
// n 的初始值为0,setN 不改变 n ,setN 后得到一个新的 n
const [n ,setN] = React.useState(0);
return (
<div className='grandson'>
Grandson n: {n}
<button onClick={() => setN(n + 1)}>+1</button>
</div>
);
}
const root = document.querySelector('#root');
ReactDOM.render(<App />, root);
多个 state 数据的情况
以下为个人理解,极大可能理解错误,待考证
有多个 state 数据时,React 将新旧虚拟DOM 不一致的部分包括其子组件一起重渲染,对于没有变化的数据,渲染时只会保留栈内存中的数据,而不保留堆内存中的数据(因为栈内存中的地址改变了,React 会重新创建一个对象,对象中没有改动的数据不在这个新对象中,就会变成 undefined)
也就是说,React 局部重渲染的是新旧虚拟DOM表示的DOM中数据的栈内存中不一致的数据
具体原理看 useState 原理
- 数据在栈内存时:
类组件:
class MyCompnent extends React.Component {
constructor() {
super();
this.state = {
n: 0,
m: 0
}
}
addN() {
// 改变 n 的值,重渲染后 m 的值不变
this.setState({ n: this.state.n + 1 });
}
addM() {
// 改变 m 的值,重渲染后 n 的值不变
this.setState({ m: this.state.m + 1 });
}
}
函数组件
const MyComponent = () => {
const [n, setN] = React.useState(0);
const [m, setM] = React.useState(0);
// 改变 n 的值,重渲染后 m 的值不变
// 改变 m 的值,重渲染后 n 的值不变
return (
<div>
n: {n} <button onClick={() => setN(n + 1)}></button>
m: {m} <button onClick={() => setN(m + 1)}></button>
</div>
)
}
- 栈内存中为地址,数据在堆内存时
类组件
class MyCompnent extends React.Component {
constructor() {
super();
this.state = {
num: {
n: 0,
m: 0
}
}
}
addN() {
// 改变 n 的值,重渲染后 m 的值变为 undefined
this.setState({
num: {n: 0}
});
}
addM() {
// 改变 m 的值,重渲染后 n 的值变为 undefined
this.setState({
num: {m: 0}
});
}
}
函数组件:
const MyComponent = () => {
const [state, setState] = React.useState({n:0, m:0});
// 改变 n 的值,重渲染后 m 的值变为 undefined
// 改变 m 的值,重渲染后 n 的值变为 undefined
return (
<div>
n: {state.n} <button onClick={() => setState({n: state.n + 1})}></button>
m: {state.m} <button onClick={() => setState({m: state.m + 1})}></button>
</div>
)
}
解决方法:使用 ‘…’ 操作符号
// 类组件
addN() {
this.setState({
...this.state.num,
num: {n: 0}
});
}
// 函数组件
<button onClick={() => setState({...state, n: state.n + 1})}></button>
外部数据 props
类组件:用 this.props.n 读
函数组件:直接读取传入参数 props.n
传 props 属性用 “” 或 {}
import React from 'react';
import ReactDOM from 'react-dom';
import './style.css';
function App() {
return (
<div className='father'>
father
{/* <Son messageForSon={1 + 1} /> */}
<Son messageForSon="Hi, my son!" />
</div>
);
}
// 类组件
class Son extends React.Component {
render() {
return (
<div className='son'>
Father to Son: {this.props.messageForSon}
<Grandson massageForGrandson="Hi, son!" />
</div>
);
}
}
// 函数组件
const Grandson = (props) => {
return (
<div className='grandson'>
Father to Son: {props.massageForGrandson}
</div>
);
}
const root = document.querySelector('#root');
ReactDOM.render(<App />, root);