ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 前言 本教程将细致的讲解react中所有可能用到的基础知识点。 ## jsx ### 基本了解 React 使用 JSX 来替代常规的 JavaScript。JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。 我们不需要一定使用 JSX,但它有以下优点: * JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。 * 它是类型安全的,在编译过程中就能发现错误。 * 使用 JSX 编写模板更加简单快速。 ### 基本使用 我们需要一个根元素包过它,同时需要在外部一个元素来插入这个元素。 ~~~ ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') ); ~~~ ### 单独的文件 你可以在需要的时候把这个dom模板的部分单独放一个文件,hello.js,然后再需要的时候引入这个文件。 ~~~ ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') ); ~~~ ~~~ <body> <div id="example"></div> <script type="text/babel" src="hello.js"></script> </body> ~~~ ### 注意事项 你可以在其中使用表达式,但是不能写if else语句 ### 样式 你可以通过变量的方式写样式代码,不过这种一般使用不多,大多数还是写在单独的样式文件,这种方式一般是需要交互逻辑或者接口结果改变样式需求的时候这样子写。 ~~~ var myStyle = { fontSize: 100, color: '#FF0000' }; ReactDOM.render( <h1 style = {myStyle}>菜鸟教程</h1>, document.getElementById('example') ); ~~~ ### 注释 注释需要写在花括号中,实例如下: ~~~ <h1>菜鸟教程</h1> {/*注释...*/} ~~~ ### 对数组的支持 支持数组的默认展开,不需要额外的去遍历。 ~~~ var arr = [ <h1>菜鸟教程</h1>, <h2>学的不仅是技术,更是梦想!</h2>, ]; ReactDOM.render( <div>{arr}</div>, document.getElementById('example') ); ~~~ ### h5标签&&react标签 要渲染 HTML 标签,只需在 JSX 里使用小写字母的标签名。 ~~~ var myDivElement = <div className="foo" />; ReactDOM.render(myDivElement, document.getElementById('example')); ~~~ 要渲染 React 组件,只需创建一个大写字母开头的本地变量。 ~~~ var MyComponent = React.createClass({/*...*/}); var myElement = <MyComponent someProperty={true} />; ReactDOM.render(myElement, document.getElementById('example')); ~~~ ### 使用js表达式 你可以在任何需要的jsx文档中使用js的表达式,表达式要写在大括号中 `const ele=<div>{1+2}rem</div>` ### jsx的属性 属性中的字符串值用双引号,属性中变量也是用{},属性中的名字要用驼峰,比如onClick,className,tabIndex ### jsx的嵌套 同html一样,jsx也支持元素嵌套。如果的你的标签是闭合的,结尾用/结束 ~~~ const dialog=<img src={img.url}/> const ele=( <div> <h1></h1> <ul> </ul> </div> ) ~~~ ## 元素渲染 ### 基本元素渲染 render()方法会渲染一个基本的react元素,如果你觉得它不方便使用,你可以定义为变量。 ~~~ const div=<div>hello world </div> ReactDom.render(div,mountNode) ~~~ ### react只会更新变化的部分 ### 可以通过多次调用react组件实现基本的更新 ## 组件&&props ### 基本使用 通过creatClass创建类,如果我们需要传递数据,通过this.props 对象传递.(组件的第一个字母必须大写) > 注意事项:在添加属性时, class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。 ~~~ function Welcome(props) { return <h1>Hello, {props.name}</h1>; } var HelloMessage = React.createClass({ render: function() { return <h1>Hello World!{{this.props.name}}</h1>; } }); ReactDOM.render( <HelloMessage name='zhangsan' />, document.getElementById('example') ); ~~~ ### 复合组件 我们可以通过创建多个组件来合成一个组件,即把组件的不同功能点进行分离。组件名不一定是用单标签,也可以是双标签。(xml的特点是有且只有一个根节点) ~~~ var WebSite = React.createClass({ render: function() { return ( <div> <Name name={this.props.name} /> <Link site={this.props.site} /> </div> ); } }); var Name = React.createClass({ render: function() { return ( <h1>{this.props.name}</h1> ); } }); var Link = React.createClass({ render: function() { return ( <a href={this.props.site}> {this.props.site} </a> ); } }); ReactDOM.render( <WebSite name="菜鸟教程" site=" http://www.runoob.com" />, document.getElementById('example') ); ~~~ ## 事件处理 ### 写法 react中的事件必须使用驼峰,并且申明的事件需要this申明,并且如果es6的方式需要申明绑定 ~~~ handleClick(){ } constructor(props){ super(props); this.handleClick=this.handleClick.bind(this); } render (){ return ( <button onClick={this.handleClick}></button> ) } ~~~ ### 阻止默认事件 ~~~ handleClick(e){ e.preventDefault() } ~~~ ### 改变组件状态 ~~~ handleClick(e){ this.setState({ value :e.target.value }) } ~~~ ### 事件中你可以写箭头函数,可以支持传入参数,定义函数时事件函数是在末尾的 ~~~ handleClick(name,e){ console.log(name) } <button onClick={(e)=>this.handleClick(e)}></button> <button onClick={(e)=>this.handleClick(name,e)}></button> ~~~ ## 条件渲染 ### 你可以根据某些条件来完成条件渲染 一般是根据state进行的,甚至你可以控制返回不同的元素 ~~~ class Toggle extend React.Component{ constructor (props){ super(props); this.state={isLike:false} } render (){ var text =this.state.isLike?true:false; if(text){ return <span>喜欢很多,喜欢周杰伦</span> }else{ return <span>不喜欢,</span> } } } ~~~ ### 与运算符 你可以通过与运算符来决定某个元素是否显示 ~~~ render (){ var text =this.state.isLike?true:false; return ( { text && <span>喜欢</span>} ) } } ~~~ ### 三目渲染,做判断然后根据条件进行选择性的渲染 ~~~ render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in. </div> ); } ~~~ ### 阻止组件渲染 主要是通过没有某个属性或者属性不符合需求的时候返回null实现不渲染的 ~~~ class Title extends Component{ render (){ if(!this.props.warn){ return null; } return ( <span>{this.props.warn}</span> ) } } ~~~ ### 组件Api 在之前的知识中,我们改变组件状态都通过setState()的方式实现。下面我们详细讲解它提供了那些方式可以实现组件的一些状态更改。 - 设置状态setState({}) setState(object nextState[, function callback]),在这个的使用中可以使用两个函数,前面的函数中可以带入setState,会自带当前state的所有参数。后面的回调函数会在设置状态并且渲染成功后执行结果(可选参数)。 ~~~ tchange(){ this.setState(function(state){ return {text:state.text} }),console.log(1) } ~~~ - 设置属性 setProps() setProps(object nextProps[, function callback]) props相当于组件的数据流,它总是会从父组件向下传递至所有的子组件中。当和一个外部的JavaScript应用集成时,我们可能会需要向组件传递数据或通知React.render()组件需要重新渲染,可以使用setProps()。 更新组件,我可以在节点上再次调用React.render(),也可以通过setProps()方法改变组件属性,触发组件重新渲染。 - 替换属性 replaceProps() replaceProps(object nextProps[, function callback]) replaceProps()方法与setProps类似,但它会删除原有props - 获取dom节点 findDOMNode() 可以用来获取一些dom节点的字段和一些简单的操作,前提是dom已经被渲染到页面中。 使用方式:(属于reactdom的方法) ~~~ var reactEle = ReactDOM.render( <App>itbilu.com</App>, document.getElementById('example') ); var element = ReactDOM.findDOMNode(reactEle); ~~~ - 判断组件挂载状态 isMounted 用来判断组件是否渲染,避免一些异步渲染数据的错误 ## 列表&&keys ### 渲染列表元素 一般是通过map遍历来实现渲染列表组件的,其中建议key要添加一下,且兄弟节点的key是不同的。 ~~~ const numbers=[1,2,2,5] render(){ return ( {numbers.map((number)=> <li key={number.toString()}>{number}</li> )} ) } ~~~ ## 表单 ### 受控组件 在react中,所以的表单组件的值不能直接获取和更改,而是要相应的状态去更改对应的值,在这个事件中,你可以对值进行对应的验证和判断,如果你针对多个控件绑定了同一个事件,你可以用e.tatget.name来进行区分,做什么处理。 ### 非受控组件 如果你觉得上面的方法比较麻烦,可以通过非受控组件完成输入框的即时更改,这时与vue的v-model以及data比较类似.同样你可以设置默认值.这里的input是整个控件中可访问的。 `<input name=name ref={(input)=>this.input=input} defaultValue="name">` ## 状态提升 ### 单组件提升父组件 在某些组件中,可能需要公用一些数据,我们建议吧这些需要的数据放进最近的父组件中统一管理和使用,称为状态提升。 ~~~ class Title extends Component{ render (){ if(!this.props.warn){ return null; } return ( <span>{this.props.warn}</span> ) } } class App extends Component{ change() { this.setState( {warn:this.warn.value} ) } render(){ return( 自定义警告内容:<input name="warn" ref={(input)=>this.warn=input}/><button type="submit" onClick={this.change}>提交</button> <Title warn={this.state.warn}/>) } } ~~~ ### 多子组件共享父组件 假设在下面的组件中,我们可以实现人民币以美元之间的互相转换,且其中一种的输入会影响另一个的显示,我们将他们的值以及影响的事件都托管在父组件中。 ~~~ class CMoney extends Component{ render (){ return ( <input value={this.props.money} onChange={this.props.change}/> ) } } class AMoney extends Component{ render (){ return ( <input value={this.props.money} onChange={this.props.change}/> ) } } class Money extends Component{ constructor(props){ super(props); this.state={amoney:'0',cmoney:'0'} this.achange=this.achange.bind(this); this.cchange=this.cchange.bind(this) } achange(e) { this.setState( { cmoney:e.target.value*7, amoney:e.target.value } ) } cchange(e) { this.setState( { cmoney:e.target.value, amoney:(e.target.value)/7 } ) } render(){ return ( c:<CMoney money={this.state.cmoney} change={this.cchange}/> a:<AMoney money={this.state.amoney} change={this.achange}/> ) } ~~~ ### 数据修改 - 直接修改数据 直接修改数据,如果是简单类型没什么问题,但是复杂数据比如对象类型的,直接修改会导致一些问题,这时候建议是用对象复制的方式。这样的好处是保留了原来的数据。 ~~~ var player={name:'张三',score:20} player.score=21; var newPlayer=Object.assign({},player,{score:21}) ~~~ - 提供历史记录 有的时候也许你需要提供用户的历史操作,那么你需要根据用户的每一步操作记录一些基本数据,然后根据每一步的操作不同,增加历史记录数据,当需要的时候返回到对应的操作即可,渲染的时候总是渲染到最新的数组数据。当然你也可以指定为跳转到指定步骤,这个主要取决于你渲染时选择的数据是什么。 ~~~ //增加步骤 this.setState({ history: history.concat([{ squares: squares }]), //回到某个历史记录 //渲染最新的数据信息 const history = this.state.history; const current = history[history.length - 1]; //跳转到指定的步骤 删除其他步骤 jumpTo(move){ this.setState({ history:this.state.history.clice(move+1)}) } ~~~ ## 组合与继承 ### 组件的嵌套 一些组件不能提前知道他们的子组件时什么,此时可能的做法是通过props.children来控制支持其子组件的显示。比如对话框,边框等 都不能完全确认子组件是什么,他们更像是容器组件,但需要预留出放子组件的部分,也就是这部分的设计思路。