React小试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
<script type="text/babel"> class App extends React.Component { constructor() { super(); this.state = { message: "hello wolrd", name: "why" }; }
btnClick() { this.setState({ message: "hello react" }) }
render() { return ( <div> <h2>{this.state.message}</h2> <button onClick={this.btnClick.bind(this)}>修改文本</button> //注意必须绑定好this </div> ) } }
const root = ReactDOM.createRoot(document.querySelector("#root")) root.render(<App/>)
|
循环写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <script type="text/babel"> const root = ReactDOM.createRoot(document.querySelector("#root"))
class App extends React.Component { constructor() { super()
this.state = { movies: ["xixi","haha", "zeze"] } }
render() { return ( <div> <h2>Movie List</h2> <ul> {this.state.movies.map(movie => <li>{movie}</li>)} </ul> </div> ) } }
root.render(<App/>)
|
JSX书写规范
jsx的使用
jsx嵌入变量作为子元素
case1:Number, String, Array类型时,可以直接显示
case2:null,undefined,Boolean类型时,内容为空
如果希望可以显示null,undefined,boolean那么需要转成字符串(调toString,或+””)
case3:Object对象类型不能作为子元素
case4:可以插入表达式(运算表达式,三元运算符,执行一个函数)
基本属性绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class App extends React.Component { constructor() { super() this.state = { title:"hahaa", imgURL: "xxxx" } }
render() { const { title,imgURL } = this.state return ( <div> <h2 title={title}>I'm h2</h2> <img src={imgURL} /> </div> ) } }
|
类绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <script type="text/babel"> class App extends React.Component { constructor() { super() this.state = { isActive: true, objStyle:{color:"red", fontsize:"30px"} } }
render() { const { isActive, objStyle } = this.state const className = `abc cba ${isActive ? 'active':''}` const classList = ["abc", "cba"] if(isActive) classList.push("active") return ( <div> <h2 className={className}>I'm h2</h2> <h2 className={classList.join(" ")}>I'm h2</h2>
<h2 style={objStyle}></h2> </div> ) }
|
React事件绑定
三种方式解决this问题
- bind给btnClick显示绑定this
- 使用ES6 class fields语法
- 事件监听时传入箭头函数(最优)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <script type="text/babel"> class App extends React.Component { constructor() { super() this.state = { message:"hello world", counter:1000 } this.btn1Click = this.btn1Click.bind(this) }
btn1Click() { console.log("btn1Clik", this); this.setState({counter: this.state.counter+1}) }
btn2Click = () => { console.log("btn2Clik", this); this.setState({counter: 1000}) }
btn3Click() { console.log("btn3", this); this.setState({counter: 3}) } render() { const { message } = this.state return ( <div> {/* 方式一:bind绑定*/} <button onClick={this.btn1Click}>按钮1</button> {/* 方式二:ES6 class fields*/} <button onClick={this.btn2Click}>按钮2</button> {/* 方式三:直接传入一个箭头函数*/} <button onClick={() => this.btn3Click()}>按钮3</button> <h2>当前计数:{this.state.counter}</h2> </div> ) } }
|
基本参数传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class App extends React.Component { constructor() { super() this.state = { message:"hello world", } }
btnClick(event, name, age) { console.log("btnClick", event, this); console.log(name, age); }
render() { return ( <div> {/* event参数的传递*/} <button onClick={this.btnClick.bind(this)}>按钮1</button> <button onClick={(event) => this.btnClick(event)}>按钮2</button>
{/*额外的参数传递*/} <button onClick={(event) => this.btnClick(event, "why", 18)}>按钮</button> </div> ) } }
|
条件渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class App extends React.Component { constructor() { super() this.state = { message:"hello world", isReady: false, friend:{ name:"kobe", desc:"xixihaha" } } }
render() { const { isReady,friend } = this.state let showElement = null if (isReady) { showElement = <h2>开始战斗</h2> } else { showElement = <h2>做好准备</h2> } return ( <div> {/*方式一:根据条件给变量赋不同的内容*/} <div>{showElement}</div> {/*方式二 :三元运算*/} <div>{isReady ? <button>开始战斗</button>:<h2>做好准备</h2>}</div> {/*方式三 :&&逻辑与运算*/} {/*friend没取到值时为null,就不显示,取到了再显示*/} <div>{ friend && <div>{friend.name+" "+friend.desc}</div>}</div> </div> ) } }
|
列表渲染
展示:map
过滤:filter
截取数组:slice
注意每个列表的子元素需要添加一个key
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class App extends React.Component { constructor() { super() this.state = { students:[ {id:111,name:"haha", score:12}, {id:222, name:"yy", score:13}, {id:333,name:"xxx", score:9}, {id:444,name:"a12", score:14}, ] } }
render() { const { students } = this.state return ( <div> <h2>学生列表数据</h2> <ul>{ Students.filer(item => item.score >10).slice(0,2).map(item => { return ( <div class="item" key={item.id}> <h2>学号:{item.id}</h2> <h2>姓名:{item.name}</h2> <h2>分数:{item.score}</h2> </div> ) })} </ul> </div> ) }
|
JSX的本质
可以通过Babel官网查看
jsx其实就React.createElement(component, props, …children)函数的语法糖
- 所有的jsx最终都会被转换成React.createElement的函数调用
createElement需要传递三个参数
- type:
- 当前ReactElement的类型
- 如果是标签元素,那么就使用字符串表示’div’
- 如果是组件元素,那么就直接使用组件的名称
- config:
- 所有jsx中的属性都在config以对象的属性和值的形式存储
- 比如传入className作为元素的class
- children
- 存放在标签中的内容,以children数组的方式进行存储
虚拟DOM
通过React.createElement最终创建出来一个ReactElement对象
这个对象组成了一个JS的对象树,也就是虚拟DOM
目的:传统Web会把数据的变化时时刚更新到用户界面,每次微小的变动都会引起DOM树重新渲染
虚拟DOM是将所有操作累加起来,基于diff算法,统计计算出所有变化后,统一更新一次DOM.虚拟DOM还可以做到跨平台,利用REACT渲染到Web端,利用其他的可以渲染到ios端
购物车案例
值得注意点:
- 数量的增删可以抽取到一个事件,通过加+1或-1来实现增删
- 条件渲染时,可以尝试代码抽取到两个函数,一个购物车不为空,购物车为空,最后在render通过一个三元运算来决定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| class App extends React.Component { constructor() { super() this.state = { message:"hello world", books:books } }
changeCount(index, count) { const newBooks = [...this.state.books] newBooks[index].count += count this.setState({ books: newBooks }) }
removeItem(index) { const newBooks = [...this.state.books] newBooks.splice(index, 1) this.setState({books: newBooks}) }
renderBookList() { const { books } = this.state const totalPrice = books.reduce((preValue, item) => { return preValue + item.count * item.price },0) return <div> <table> <thead> <tr> <th>序号</th> <th>名称</th> <th>日期</th> <th>价格</th> <th>数量</th> <th>操作</th> </tr> </thead> <tbody> { books.map((item,index) => { return ( <tr key={item.id}> <td>{index+1}</td> <td>{item.name}</td> <td>{item.date}</td> <td>{item.price}</td> <td> <button onClick={() => this.changeCount(index,-1)} disabled={item.count <= 1}>-</button> {item.count} <button onClick={() => this.changeCount(index, 1)}>+</button> </td> <td><button onClick={() => this.removeItem(index)}>删除</button></td> </tr> ) }) } </tbody> </table> <h2>总价格:{totalPrice}</h2> </div> }
renderBookEmpty() { return <div><h2>购物车空</h2> </div> }
render() { const { books } = this.state return books.length ? this.renderBookList() : this.renderBookEmpty() }
} const root = ReactDOM.createRoot(document.querySelector('#root')) root.render(<App/>) </script>
|