react
Table of Contents
1 学习的基础
- js/html/css 基础
- webpack 基础
- node 基础
2 使用环境
- webstorm 最新的
- windows10 最新的
- node 最新的
3 创建项目
3.1 下载可用于创建项目包 create-react-app
yarn add create-react-app
3.2 创建项目
当前使用的版本(3.2.0)
npx create-react-app my-react
3.3 启动项目(根据package中的命令操作)
cd my-react
yarn start
4 react 知识点
知识点测试时都是修改 App.js 文件中的内容
import React from 'react'; function App() { return ( ...修改的入口参考位置 ) } export default App;
使用 jsx 语法,jsx: javascript xml,变成js需要编译转换
4.1 只能挂一个标签
4.1.1 只能一个
<h1>hello world</h1>
4.1.2 两个会报错
<p>hello</p> <p>world</p>
4.2 单标签必须自闭合(xml很严格)
<label> <span>name:</span> <input/> </label>
4.3 使用变量
4.3.1 字符串直接用
<input type="text"/>
4.3.2 使用字面量
<input type={'text'}/>
4.3.3 使用变量
const msg = 'hello world'; ...... <h1>{msg}</h1>
4.4 注释(需要使用变量形式)
<div> <span>1</span> {/*<span>111</span>*/} </div>
4.5 关键字冲突
jsx 中属性关键字和js中关键字冲突(class、for),使用其他的词代替
<div> <label htmlFor={'hd'}>name:</label> <input className={'name'} id={'hd'}/> </div>
4.6 表达式
4.6.1 字面量
<p>{123}</p>
4.6.2 求值表达式
<div> <p>1 + 1 = {1 + 1}</p> <p>1 > 2 is {(1 > 2).toString()}</p> <p>(5>2)&&(5<8) is {((5 > 2) && (5 < 8)).toString()}</p> </div>
4.7 样式style
以对象形式来使用,属性的写法使用小驼峰(去掉连接符号)
<div style={{backgroundColor:'#f00'}}>11</div>
4.8 循环
key保持不变
['张三', '李四', '王五', '马六'] .map((it, ix) => ({name: it, id: ix})) .filter(it=>it.id > 0) .map(it=>( <div key={it.id}>{it.name}</div> ))
4.9 条件渲染
<div> {2 >1 && <h1>hello world</h1>} {2 < 1 && <h1>hello world</h1>} {2 < 1 ? <h1>world</h1> : <h1>hello</h1>} </div>
4.10 组件
4.10.1 创建组件
- 必须名称首字母大写
- render 必须存在
//getter/setter 函数为了直接使用 this.xxx class Person extends React.Component { constructor(props) { super(props); this._name = 'master'; this._age = 100; } get name() { return this._name; } set name(new_name) { this._name = new_name; } get age() { return this._age; } set age(new_age) { this._age = new_age; } render() { return ( <div> <h2>name: {this.name}</h2> <h2>age: {this.age}</h2> </div> ); } }
4.10.2 使用组件
直接当成一个标签使用
<Person/>
4.10.3 组件嵌套
直接使用Teacher组件,Teacher组件中使用了Student组件
class Student extends React.Component { render() { return ( <span>学生</span> ); } } class Teacher extends React.Component { render() { return ( <div> <h1>teacher</h1> { [1, 2, 3, 4, 5] .map(it=>({name:it, id:'s' + it})) .map(it=>( <div key={it.id}> <Student/> {it.name} </div> )) } </div> ); } }
4.10.4 组件传值
- 简单使用
class Person extends React.Component { constructor(props) { super(props); } render() { return ( <div> <h1>name: {this.props.name}</h1> <h1>age: {this.props.age}</h1> </div> ); } } ...... <Person name={'Mrs Li'} age={25}/>
- 嵌套传参
//组件 class Item extends React.Component { constructor(props) { super(props); } render() { return ( <p>{this.props.desc}: {this.props.text}</p> ); } } class StudentList extends React.Component { constructor(props) { super(props); } render() { return ( this.props.list.map(item => ( <ul key={item.id}> <li>class: {item.class}</li> <li> <ul> <li> <span>members: </span> { item.members.map(it => ( <span key={it.id}> {it.name} </span> )) } </li> </ul> </li> </ul> )) ); } } class Teacher extends React.Component { constructor(props) { super(props); } render() { return ( <div> <Item text={this.props.name} desc={'name'}/> <Item text={this.props.age} desc={'age'}/> <Item text={this.props.job} desc={'job'}/> <p>students-list</p> <StudentList list={this.props.students}/> </div> ) } } ......(数据) const data = { name: 'Mrs Li', age: 55, job: 'teacher', students: [ { class: '031', members: ['zhou', 'fru', 'mike'] }, { class: '037', members: ['张三', '李四', '王五'] }, { class: '007', members: ['Bob', 'Alex'] } ] }; data.students.forEach((item, index) => { item.id = 's' + index; item.members = item.members.map((it, ix) => ( {id: 't' + ix, name: it} )); }); ......(使用) <Teacher name={data.name} age={data.age} job={data.job} students={data.students}/>
4.11 事件
4.11.1 this 丢失
4.11.2 事件名称使用小驼峰
class Event extends React.Component { click() { console.log('clicking', window.Date.now()); } render() { return ( <h1 style={{textAlign: 'center'}} onClick={this.click.bind(this)}>点击</h1> ); } } ...... <Event/>
4.12 手动触发渲染更新
4.12.1 强制更新
很可能会影响效率,不推荐使用
class Count extends React.Component { constructor() { super(); this.val = 0; } click() { ++this.val; console.log('click', this.val); this.forceUpdate(); } render() { return ( <div style={{textAlign: 'center'}}> <p> <span>click times: {this.val}</span> </p> <p> <input onClick={this.click.bind(this)} type='button' value='点击'/> </p> </div> ); } } ...... <Count/>
4.12.2 state 的方式
class Count extends React.Component { constructor() { super(); this.state = { val: 0 }; } click() { this.setState({ val: this.val + 1 }); } get val() { return this.state.val; } render() { console.log('rendering', window.Date.now()); return ( <div style={{textAlign: 'center'}}> <p> <span>click times: {this.val}</span> </p> <p> <input onClick={this.click.bind(this)} type='button' value='点击'/> </p> </div> ); } } ...... <Count/>
4.12.3 父组件传递给子组件的参数会同步更新
子组件不能修改父组件参数,参数是复杂对象则可以改其属性
class Child extends React.Component { constructor(props) { super(props); } render() { return ( <p> 子组件: {this.props.value} </p> ); } } class Parent extends React.Component { constructor() { super(); this.state = { value: 0 }; } get value() { return this.state.value; } click() { this.setState({ value: this.value + 1 }); } render() { return ( <div> <p> 父组件: {this.value} </p> <Child value={this.value}/> <p> <input onClick={this.click.bind(this)} value={'点击'} type={'button'}/> </p> </div> ); } } ...... <Parent/>
4.13 children
4.13.1 使用儿子的形式,最里面的一层是标签的内容,是个字符串
4.13.2 组件也是类似的,就是替换了一个标签
4.13.3 儿子没有则为空,多个则是一个数组(树节点)
4.13.4 元素中的属性生成对应的参数
const a = <h1> <p style={{background: '#f86'}}> <span>color</span> </p> </h1>; const b = a.props.children; const c = b.props.children; const d = b.props.style; ...... {c} {b} {a} <p>background: {d.background}</p>
4.14 子组件根据父组件参数发请求获取参数
4.14.1 很容易出现 update 循环,update 之后获取数据继续 update
处理方法:在 shouldComponentUpdate 中控制更新
class Child extends React.Component { constructor(props) { super(props); this.state = { time: -1 }; this.request(); } shouldComponentUpdate(nextProps, nextState, nextContext) { console.log(nextProps, nextState) return nextProps.val !== this.props.val || this.state.time !== nextState.time; } componentDidUpdate(prevProps, prevState, snapshot) { this.request(); } request() { setTimeout(() => { this.setState({ time: this.props.val }); }, 500); } render() { console.log('rendering'); return ( <div> <p>click times: {this.props.val}</p> <p>time: {this.state.time}</p> </div> ); } } class Parent extends React.Component { constructor(props) { super(props); this.state = { val: 0 }; console.log('constructor') } componentDidCatch(error, errorInfo) { console.log('catch') } componentDidMount() { console.log('mount'); } componentDidUpdate(prevProps, prevState, snapshot) { console.log('update'); } componentWillUnmount() { console.log('unmount'); } shouldComponentUpdate(nextProps, nextState, nextContext) { console.log('should update'); // console.log(nextProps, nextState, nextContext) return true; } click() { this.setState({ val: this.state.val + 1 }); } render() { console.log('render'); return ( <div> <Child val={this.state.val}/> <p> <input type={'button'} onClick={this.click.bind(this)} value={'click'}/> </p> </div> ); } }
4.14.2 在父组件中获取数据传入子组件则没有 update 循环(看情况选择)
4.15 子组件向父组件传参
使用调用函数的方式传递参数
class Child extends React.Component { constructor(props) { super(props); this.cnt = 0; } clickHandler() { this.props.message('msg--' + ++this.cnt); } render() { return ( <div> <input value={'click'} onClick={this.clickHandler.bind(this)} type={'button'}/> </div> ); } } class Parent extends React.Component { constructor() { super(); this.state = { msg: 'waiting click' } } message(msg) { this.setState({ msg }); } render() { return ( <div> <p>message: {this.state.msg}</p> <Child message={this.message.bind(this)}/> </div> ); } } ...... <Parent/>
4.16 引用(可操作组件)
ref 值重复会覆盖,最有一个有效
4.16.1 简单引用
组件也同样适用
class Reference extends React.Component { componentDidMount() { console.log(this.refs.test.id); } render() { return ( <div> <input ref={'test'} id={123}/> </div> ); } } ...... <Reference/>
4.16.2 父组件使用子组件的数据
class Child extends React.Component { constructor(props) { super(props); this.val = 'child' + this.props.id; } render() { return ( <div> <p>{this.val}</p> </div> ); } } class Parent extends React.Component { componentDidMount() { console.log(this.refs.first_child.val); console.log(this.refs.second_child.props.id); } render() { return ( <div> <Child ref='first_child' id={1}/> <Child ref='second_child' id={2}/> </div> ); } } ...... <Parent/>
4.16.3 子组件使用父组件的数据
就是个普通的参数传递
class Child extends React.Component { render() { return ( <div> <p>{this.props.parent.val}</p> </div> ); } } class Parent extends React.Component { constructor() { super(); this.val = 'parent'; } render() { return ( <div> <Child parent={this}/> </div> ); } } ...... <Parent/>
4.17 受控表单元素
4.17.1 input,select 作为输入,绑定了 value
4.17.2 原始用法使用 defalutValue 来替代 value
4.17.3 受控的表单元素需要绑定 change 事件
class Form extends React.Component { constructor() { super(); this.state = { val: '' }; } handlerChange(event) { this.setState({ val : event.target.value }); } render() { return ( <div> <p> <input type={'text'} onChange={this.handlerChange.bind(this)} value={this.state.val} placeholder={'请输入名称'}/> </p> <p> <input defaultValue={'默认值'}/> </p> <p> <input type={'password'} placeholder={'请输入密码'}/> </p> </div> ); } } ...... <Form/>
Created: 2019-11-29 周五 23:11