[TOC] [组件 & Props](https://react.docschina.org/docs/components-and-props.html) ## :-: 自定义组件 :-: **特别注意:组件的名称首字母必须大写** * 1.函数组件 * 通过函数返回一个元素 使用jsx语法(推荐):`function MyFuncComp(){ return <h1>jsx</h1> }` 通过React.createElement方法构建:`function MyFuncComp() { return React.createElement('h1', { style: { color: 'red' } }, 'createElement'); }` * 2.类组件(功能更强大) * 必须继承React.Components * 必须提供rander函数,用于渲染 ``` import React, { Component } from 'react'; export default class classComp extends Component { // ··· render() { return ( <h1>Demo</h1> ) } } ``` ## :-: React - 无状态组件 ``` // 函数组件 function component() { return <div>我是一个函数组件</div>; } ReactDOM.render(component(), document.getElementById("root")); // 标签组件(首字母必须大写) function App() { return <div>我是一个标签组件</div>; } ReactDOM.render(<App />, document.getElementById("root")); ``` ## :-: 组件传参(props) ### 注意: * 组件的属性应当使用小驼峰命名法。 * 数据传递为单向数据流。 * 组件无法改变自身的属性(props)(数据属于谁,谁才用权利改动它) ``` ReactDOM.render(<TagList data={"传参"} />, document.getElementById("root")); -------------------------------------------------------------- import React from "react"; function TagList(props) { console.log(props); // { data:'传参' } return <div>我是一个组件 --{props.data}</div>; } export default TagList; ``` ## :-: 组件状态(state) ### 注意事项 * 组件可以自行维护的数据 * 组件状态仅在类组件中有效 * 状态(state),本质上是类组件的一个属性,是对象类型 * 需要初始化,有两种方式 * 不能直接改变状态,因为React无法监控到状态发生了改变。 * 所以需要通过this.setState({})方法,使改变状态后的值重新渲染视图、 * 一但调用了this.setState(),会导致组件重新渲染、 ### 组件的数据分两种 1. 参数(props) -- 该数据是其他组件传递的,所有权不属于组件自身,因此组件无法改变数据(只读) 2. 状态(state) -- 该组件是由自身创建的,所有权属于组件自身,组件有权限改变数据。(其他任何组件都无法改变) ``` ReactDOM.render(<TestComp timer={60} />, $root); -------------------------------------------------------------- import React, { Component } from 'react'; // 组件状态(state) export default class TestComp extends Component { // 实际上React会自动加constructor构造函数,super(props) constructor(props) { super(props); // 第一种初始化状态的方式(状态是必须要初始化的) this.state = { left: this.props.timer } this.time = setInterval(() => { // 重新渲染 (一定要调用this.setState方法来改变原数据,不能直接修改数据,不然React监控不到变化) this.setState({ // 数据混合 (React会将前后数据对比覆盖原有的数据并渲染到试图) left: (this.state.left - 1) }); if (this.state.left <= 0) clearInterval(this.time); }, 100); } // 第二种初始化状态的方式(还在测试阶段,没有正式纳入js标准) state = { left: this.props.timer } // 初始化状态 JS Next语法 render() { return ( <h1>倒计时剩余:{this.state.left}</h1> ) } } ``` ## :-: React - 类组件 ``` import React from "react"; // extends React.Component -- 继承React的生命周期 class TodoList extends React.Component { // handleClick = this.handleClick.bind(this); // 状态 // constructor() { // super(); // this.state = { // list: [1, 2, 3] // }; // } // 上面的this.state === 下面的state、 // 状态 state = { inpVal: "123", list: [1, 2, 3, 4, 5], count: 0 }; // 必须要有 render 方法 render(h) { return ( <> {/* this === TodoList */} <div> {/* onChange={this.handleChange.bind(this)} */} <input type="text" value={this.state.inpVal} onChange={this.handleChange} /> <button onClick={this.handleClick}>添加</button> </div> <div> <ul> {this.state.list.map((item, index) => { return ( <li key={index}> {item} <button onClick={() => { this.handleDelete(index); }} > 移除 </button> </li> ); })} </ul> </div> <div> <span>{this.state.count}</span> <button onClick={this.handleAdd}>Add</button> </div> </> ); } handleChange = e => { this.setState({ inpVal: e.target.value }); }; handleClick = () => { this.setState({ list: [...this.state.list, this.state.inpVal], inpVal: "" }); }; handleDelete = index => { const list = this.state.list; list.splice(index, 1); this.setState(list); }; handleAdd = () => { // 不能这样写,React会做批量更新处理。将相同的操作合并成一个、所以结果为3 // this.setState({ count: this.state.count + 1 }); // this.setState({ count: this.state.count + 2 }); // this.setState({ count: this.state.count + 3 }); // 正确的做法是 this.setState(prevState => { return { count: prevState.count + 1 }; }); this.setState(prevState => { return { count: prevState.count + 2 }; }); this.setState(prevState => { return { count: prevState.count + 3 }; }); }; } export default TodoList; ``` ## :-: 受控组件 与 非受控组件 ``` import React from "react"; class Control extends React.Component { state = { list: [] }; render() { return ( <> {/* 非受控组件 */} <div> taskA: <input type="text" ref={dom => { this.taskA = dom; }} /> <button name="taskA" onClick={this.handleClick}> 添加A任务 </button> </div> <div> taskB: <input type="text" ref={dom => { this.taskB = dom; }} /> <button name="taskB" onClick={this.handleClick}> 添加B任务 </button> </div> <div> <ul> {this.state.list.map((item, index) => ( <li key={index + item}>{item}</li> ))} </ul> </div> </> ); } handleClick = e => { const type = e.target.name; let task = this[type].value; this[type].value = ""; if (type === "taskA") { task = `任务A:${task}`; } else if (type === "taskB") { task = `任务B:${task}`; } this.setState({ list: [...this.state.list, task] }); }; } export default Control; ```