JSX
一. 引入方法
- CDN引入
create-react-app
$ yarn global add create-react-app $ create-react-app demo $ cd demo $ yarn start
二. 语法const element = <div> hello world </div>
三. 注意事项
- className而不是class
<div className="red"></div>
插入变量
标签里所有的变量都要用{}
包起来- 如果需要变量n 写成
{n}
- 如果需要对象,写成
{ { name:"oliver" } }
- 如果需要变量n 写成
return 后边一定要加()
const App = ()=>{ return( <div>我是App</div> ) } //不写括号会报错,相当于return undefined;
四. 条件判断
- React的JSX完全**就是JS的写法!
如果你想省事儿,可以这样写
const App = ()=>{
return (
<div>
{ n%2==0? <div>我是偶数</div> : <div>我是奇数</div>}
</div>
)
}
如果你想有条理点,可以这样写
const App = ()=>{
const el = n%2==?:<div>我是偶数</div> : <div>我是奇数</div>
return(
<div> {el} </div>
)
}
如果你想多分支判断,可以这样写
const App = ()=>{
const el
if(n==1){ el = <div>第一名</div> }
else if(n==2){ el = <div>第二名</div> }
else if(n==3){ el = <div>第三名</div> }
return (
<div> {el} </div>
)
}
五. 循环语句
1.for循环
const App = (props)=>{
const arr = []
for(let i=0; i<props.list.length; i++){
arr.push(<div> 下标为{i},值为{props.list[i]} </div>)
}
return (
<div> {arr} </div>
)
}
2.同理for循环可以改为
props.list.map((n,item)=>{
return <div>下标{index},值为{n}</div>
})
3.双重循环
render(){
return(
listA.map((val.idx)=>{
<div>
{
listB.map((value,index)=>{
return <button />
})
}
</div>
})
)
}
html标签后的代码要写在{}
内
Vue 和 React 最大的区别就是:
- 你愿意用Vue给你写好的 v-xxx
- 还是愿意用React自己写JS代码
React组件
一. Element V.S Component
//这是一个react元素(默认小写开头
const div = <div className="el"> element </div>
//这是一个react组件(默认大写开头
const Div = ()=>{
return <div className="cpn"> component </div>
}
二. 什么是组件
- 就目前而言,一个返回react元素的函数,就是组件
三. React两种组件
(一)函数组件
//声明方法
function Welcome(props){
return <h1>Hello, {props.name}</h1>
}
//使用方法
<Welcome name="Oliver"/>
(二)class(类)组件
//声明方法
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>
}
}
//使用方法
<Welcome name="Oliver"/>
注意,函数组件没有this,一律使用变量和参数
四. 添加props(外部数据)
类组件
<Demo name="Oliver"/> ... class Demo extends React.component{ render( <div> 名字:{this.props.name} </div> ) }
直接读取属性
this.props.xxx
函数组件
<Demo name="Oliver"/> ... const Demo = (props)=>{ return <div> 名字:{props.name} </div> }
子组件改父组件的值:需要父组件同时传入父组件的值,和修改对应值得函数。
//父组件 <Children counter={number} countFn={add}/> const add = ()=>{ setNumber(number+1) } //子组件 props:['counter','add'] ... <div>{counter}</div> <button onClick={add}>+1<button/>
直接读取参数
props.xxx
五. 添加state(内部数据)
类组件
- 读:
this.state.xxx
写:
//方法1 this.setState({ n: this.state.n+1 }) //方法2 推荐!! this.setState((state)=>{ const n = this.state.n+1 return {n} })
setState注意事项:
this.setState.n += 1
无效setState
会异步更新UI, n的值不会立刻改变。推荐setState((state)=>{return{...}})
函数方式- 这是一种函数式理念
- 读:
函数组件
使用了React Hook的API
用useState返回数组,第一项用来读,第二项用来写const [n, setN] = useState(0); ... return ( <div>{n}</div> <button onClick={()=>setN(n+1)}>+1</button> ) ...
复杂数据的state
类组件的setState会自动合并第一层的属性
this.state={ m:0, n:0 } ... this.setState( {n:0} ) //会自动将m的值合并,而不会初始化m为undefined
类组件的第二层要用 "
...
"this.state={ user:{ name:"oliver", age:18 } } ... //修改年龄 this.setState({ user:{ ...this.state.user, //将原始数据都拷贝过来 age: 19 } })
函数组件完全不会帮你合并,数据只有一层时分别操作:
let [n,setN] = React.useState(0) let [m,setM] = React.useState(0) ... <button onClick={()=>setN(n+1)}></button> <button onClick={()=>setM(m+1)}></button>
函数组件有两层时:
- 用"
...
" - 深拷贝
let obj1 = JSON.parse(JSON.stringify(obj))
,然后再进行修改传值
let [myState,setMyState] = useState({ name: "oliver", age: 18 }) //修改年龄 setMyState({ ...myState, age: 19 })
- 用"
事件绑定
类组件的事件绑定
class App extends React.component{ //绑定addN事件,并挂载到实例上 addN = ()=> this.setState({n:this.state.n+1}) constructor(){ super() } ... render(){ return ( <button onClick={this.addN}>add</button> ) } }
或者
class App extends React.component{ constructor(){ super() } addN(){ this.setState({n:this.state.n+1}) } ... render(){ return ( <button onClick={this.addN.bind(this)}>add</button> ) } }
函数组件的事件绑定
const App = ()=>{ sayHi = ()=> { console.log('hi') } return ( <button onClick={sayHi}></button> ) }
createElement
第一个参数:
- 字符串,如
'div'
,则创建一个<div></div>
- 函数(函数组件),则调用该函数,取得返回值作为第一个参数值
- 类(类组件),则new一个该类的实例,并且调用实例上的
render()
方法取得返回值作为第一个参数。
- 字符串,如
- JSX语法里的<div></div> 等价于
React.createElement('div')
声明周期
建议使用的生命周期
class Component extends React.Component {
//组件实例化后执行
constructor(){}
// 初始化和 update 时被调用
// 静态函数,无法使用 this。
// 一般用于根据props修改state
static getDerivedStateFromProps(nextProps, prevState) {}
// 判断是否需要更新组件
// 可以用于组件性能优化
shouldComponentUpdate(nextProps, nextState) {}
//根据vnode生成dom
render()
// 组件被挂
载后触发
componentDidMount() {}
// 替换 componentWillUpdate
// 可以在更新之前获取最新 dom 数据
getSnapshotBeforeUpdate() {}
// 组件更新后调用
componentDidUpdate() {}
// 组件即将销毁
componentWillUnmount() {}
// 组件已销毁
componentDidUnMount() {}
}
挂载
constructor
- 即组件的 实例化时机,通常可以用来设置初始化
state
;
- 即组件的 实例化时机,通常可以用来设置初始化
static getDerivedStateFromProps(nextProps, prevState)
- 在组件的模板渲染中,我们通常使用的数据为
state
和props
,而props
由父级传入,组件本身并无法直接修改,因此唯一的常见需求就是: 根据父级传入的props
动态修改state
。该生命周期就是为此而生; 大家可能会有疑问: 该方法为什么为静态方法? 而不是常规的实例方法呢?
- 先肯定一点: 使用实例方法肯定也是能满足需求的。但这个钩子比较特殊,它的执行时机是位于 新状态合并之后,重渲染之前,而且该方法会 侵入更新机制 中。如果在之中做例如修改状态之类的操作是十分不可控的。当设计为静态方法后,函数内部便无法访问组件实例,成为一个 纯函数,便能保证更新流程的安全与稳定。
- 在组件的模板渲染中,我们通常使用的数据为
render()
- 根据
state
和props
,生成 虚拟DOM;
- 根据
componentDidMount()
- 组件被创建成真实元素并渲染后 被调用,此时可获取真实的元素状态,主要用于业务逻辑的执行,例如数据请求,事件绑定等;
更新
static getDerivedStateFromProps(nextProps, prevState)
shouldComponentUpdate(nextProps, nextState)
- 上篇文章中的
diff
优化策略中有提到: 为了减少 无谓的更新消耗,赋予组件一个可以 主动中断更新流 的API
。根据参数中的 更新属性 和 更新状态,业务方自行判断是否需要继续往下执行diff
,从而能有效地提升 更新性能; 大家记得 React 中有种组件叫 纯组件(
PureComponent
) 吧,其实这个类继承于普通的Component
上封装的,可以减少多余的render
,提升性能。- 默认使用
shouldComponentUpdate
函数设定更新条件: 仅当props
和state
发生改变时,才会触发更新。这里使用了Object
浅层比对,也就是仅做第一层比对,即 1. key 是否完全匹配;2. value 是否全等; 所以如果需要超过一层的数据变动,纯组件即无法正确更新了; - 这也是为什么 React 提倡使用 不变数据 的原理,能有效地使用浅层比对;
- 不变数据: 提倡数据不可变,任何修改都需要返回一个新的对象,不能直接修改原对象,这样能有效提高比对效率,减少无谓性能损耗。
- 默认使用
- 上篇文章中的
render()
getSnapshotBeforeUpdate(prevProps, prevState)
- 替换旧版的
componentWillUpdate
,触发时机点: 在数据状态已更新,最新VNode
已生成,但 真实元素还未被更新; - 可以用来在 更新之前 从真实元素或状态中获取计算一些信息,便于在更新后使用;
- 替换旧版的
componentDidUpdate(prevProps, prevState, snapshot)
- 组件更新完成后调用;
- 可以用于 监听数据变化,使用
setState
时必须加条件,避免无限循环;
卸载
componentWillUnmount()
- 组件即将被销毁。通常可以用于 解绑事件、清除数据、释放内存 等功能
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。