Element 和 Component
const div = React.createElement('div',......) React元素,d小写
const Div = ()=>React.createElement('div',......) React组件,D大写
在React里,只要一个函数返回一个React元素,就是React组件
是不是元素是看自己本身,而不是后代,div就是Element,就算里面有个span,div还是元素
函数组件
function Welcome(props){
return <h1>Hello, {props.name}</h1>;
}
使用方法
<Welcome name="frank"/>
函数组件,Welcome(函数名),接收一个外部数据(props)外部数据放在一个参数里,是一个参数的变量
返回一个标签,自动变成React.createElement('h1',...)
当成标签使用,自动变成key,value
类组件
class Welcome extends React.Component{
render(){
return <h1>Hello, {this.props.name}<h1>
}
}
使用方法
<Welcome name="frank"/>
extends(继承),继承的没有变量,在this上拿到props
<Welcome /> React.createElement(Welcome)
<div /> React.createElement('div')
原生元素写字符串,自定义写函数名,babel online(翻译React代码网站)
React.createElement 的逻辑
如果传入一个字符串'div',则会创建一个div
如果传入一个函数,则会调用该函数,获取其返回值
如果传入一个类,则在类前面加个 new
这会导致执行constructor,获取一个组件对象,然后调用对象的render方法,获取其返回值
class Welcome extends React.Component{
constructor(){ //new对应的函数,初始化在这里面写
super() //必须写
this.state = {n:0} //在构造函数中写初始化 state
}
render(){
return <div>hi</div>
}
}
new Welcome()
实例,使用类和函数实现加1功能
function App(){
return (
<div className="App">
爸爸
<Son />
</div>
);
}
class Son extends React.Component{
constructor() { //初始化
super();
this.state = { //state是vue里的data 数据
n:0
};
}
add(){
this.setState({n: this.state.n + 1});
}
render(){ //渲染
return (
<div className="Son">
儿子 n:{this.state.n}
<button onClick={() => this.add()}>+1</button>
<Grandson />
</div>
);
}
}
const Grandson = () => {
const [n, setN] = React.useState(0); //n代表0,初始值,n是读 ,setn写
return ( //setn之后得到一个新的n,不是在原来的n上面修改
<div className="Grandson">
孙子 n:{n}
<button onClick={() => setN(n+1)}>+1</button>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
析构函数
const [n, setN] = React.useState(0); 析构函数,等价于下面代码
声明一个state,初始值为0,用n代表0,用setN修改n,setN之后得到一个新的n,不修改原来的n
const array = React.useState(0); 声明一个数组,初始值为0
const n = array[0] 读这个n,n是数组下标0
const setN = array[1] 写这个n,等于数组的下标1
添加prpos(外部数据)
类组件直接读取属性 this.props.xxx
函数组件直接读取参数 props.xxx
类组件外部数据写法: <Grandson messageForGrandson="孙子你好" />
函数组件外部数据写法: const Grandson = (props) => {}
外部数据会自动变成第一个对象,放到第一个参数上,props可以叫任意名字
function App() {
return (
<div className="App">
爸爸
<Son messageForSon="儿子你好" />
</div>
);
}
class Son extends React.Component {
render() {
return (
<div className="Son">
我是儿子,我爸对我说[{this.props.messageForSon}]
<Grandson messageForGrandson="孙子你好" />
</div>
);
}
}
const Grandson = props => {
return (
<div className="Grandson">
我是孙子,我爸对我说[{props.messageForGrandson}]
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
添加 state(内部数据)
类组件用 this.state读,this.setState写
函数组件用 useSate返回数组,第一项读,第二项写
类组件初始化state
class Son extends React.Component{
constructor(){ //new对应的函数,初始化在这里面写
super() //必须写
this.state = {n:0} //在构造函数中写初始化 state,this.state等于一个对象,值为n:0
}
render(){
return <div>hi</div>
}
}
new Welcome()
add(){
this.setState((state) =>{
return {
n:state.n + 1
}
})
}
初始化,在constructor里super下面初始化state
读, 用this.state.n读
写, 调用add()函数
setState是一个异步更新UI的过程,先把n给React,n是之前的n,所有代码都执行完才会更新n
用函数写法会传新的n,同步更新,用this.setState写,写的时候使用新的对象,不要在原有的对象上修改
函数组件用state
const Grandson = () => {
const [n, setN] = React.useState(0); //要使用state,使用React.useState(0)给一个初始值0
return (
<div className="Grandson">
孙子 n:{n} //读,使用时
<button onClick={()=> setN(n + 1)}>+1</button> //写,直接setN(n + 1)
</div> //setN不会改变n,会产生一个新的n
);
}
返回数组的第一项,就是用来读的n,第二项用来写的
完整代码
function App() {
return (
<div className="App">
爸爸
<Son />
</div>
);
}
class Son extends React.Component{
constructor(){
super();
this.state = {
n:0
};
}
add(){
this.setState((state) =>{
return {
n:state.n + 1
}
})
}
render(){
return (
<div className="Son">
儿子 n:{this.state.n}
<button onClick={()=> this.add()}>+1</button>
<Grandson />
</div>
);
}
}
const Grandson = () => {
const [n, setN] = React.useState(0);
return (
<div className="Grandson">
孙子 n:{n}
<button onClick={()=> setN(n + 1)}>+1</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
类组件 会等一会改变n
函数组件永远不会改变n
组件注意事项
类组件
this.state.n += 1 无效
其实n已经改变了,只不过UI不会自动更新而已
调用setState才会触发更新UI(异步更新),因为React没有像Vue监听data一样监听state
setState会异步更新UI,setState之后,state不会马上改变,立马读state会失败
推荐方式是setState(函数):setState({n : state.n + 1})
函数组件
跟类组件类似的地方,通过setN(新值)来更新UI
跟类组件不同的地方,没有this,一律用参数和变量
复杂 state(state里不只有n)
类组件里有n和m
class组件里的setState,如果对其中一部分修改,其它部分会自动沿用上一次的值,而不会被undefined覆盖
addN(){this.setState({...this.state, n: this.state.n + 1})}
...this.state三个点复制之前的值
const user = Object.addign({}, this.state.user)
{}是一个新对象,把之前的属性(this.state.user)复制到新对象上,然后等于user;等价于
const user = {}
const user = {...this.state.user}
function App(){
return (
<div className="App">
爸爸
<Son />
</div>
);
}
class Son extends React.Component{
constructor(){
super();
this.state = {
n: 0,
m: 0
};
}
addN(){
this.setState({n: this.state.n + 1});
}
addM(){
this.setState({n: this.state.n + 1});
}
render(){
return(
<div className="Son">
儿子 n: {this.state.n}
<button onClick={() => this.addN()}>n+1</button>
m: {this.state.m}
<button onClick={() => this.addM()}>m+1</button>
<Grandson />
</div>
);
}
}
const Grandson = () =>{
const [n, setN] = React.useState(0);
return (
<div className="Grandson">
孙子 n:{n}
<button onClick={() => setN(n + 1)}>+1</button>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDom.render(<App />, rootElement);
...或Object.assign复制属性
类组件的setState会自动合并第一层属性,不会合并第二层属性
function App() {
return (
<div className="App">
爸爸
<Son />
</div>
);
}
class Son extends React.Component {
constructor() {
super();
this.state = {
n: 0,
m: 0,
user: {
name: "frank",
age: 18
}
};
}
addN() {
this.setState({ n: this.state.n + 1 }); // m 会被覆盖为 undefined 吗?
}
addM() {
this.setState({ m: this.state.m + 1 }); // n 会被覆盖为 undefined 吗?
}
changeUser() {
this.setState({ // m 和 n 不会被置空
user: {
name: "jack" // age 被置空
}
});
}
render() {
return (
<div className="Son">
儿子 n: {this.state.n}
<button onClick={() => this.addN()}>n+1</button>
m: {this.state.m}
<button onClick={() => this.addM()}>m+1</button>
<hr />
<div>user.name: {this.state.user.name}</div>
<div>user.age: {this.state.user.age}</div>
<button onClick={() => this.changeUser()}>change user</button>
<Grandson />
</div>
);
}
}
const Grandson = () => {
const [n, setN] = React.useState(0);
return (
<div className="Grandson">
孙子 n:{n}
<button onClick={() => setN(n + 1)}>+1</button>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
函数组件里有n和m
用对象当数据时,setState不会自动合并,使用...或Object.assign复制属性
function App() {
return (
<div className="App">
爸爸
<Son />
</div>
);
}
class Son extends React.Component {
constructor() {
super();
this.state = {
n: 0,
m: 0
};
}
addN() {
this.setState({ n: this.state.n + 1 }); // m 会被覆盖为 undefined 吗?
}
addM() {
this.setState({ m: this.state.m + 1 }); // n 会被覆盖为 undefined 吗?
}
render() {
return (
<div className="Son">
儿子 n: {this.state.n}
<button onClick={() => this.addN()}>n+1</button>
m: {this.state.m}
<button onClick={() => this.addM()}>m+1</button>
<Grandson />
</div>
);
}
}
const Grandson = () => {
const [n, setN] = React.useState(0);
const [m, setM] = React.useState(0);
return (
<div className="Grandson">
孙子 n:{n}
<button onClick={() => setN(n + 1)}>n+1</button>
m:{m}
<button onClick={() => setM(m + 1)}>m+1</button>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
事件绑定
类组件的事件绑定
class Son extends React.Component{
addN = () => this.setState({n: this.state.n + 1});
render(){
return <button onClick={this.addN}>n+1</button>
}
}
详细资料点击:React 函数组件与class 组件