title: React笔记
date: 2020-05-10 10:50:21
tags:

  • react
  • 笔记
    categories: 学习
    copyright: false
    top_img: /img/bg2.png

事件处理

你必须谨慎对待 JSX 回调函数中的 this,在 JavaScript 中,class 的方法默认不会绑定 this。如果你忘记绑定 this.handleClick 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined

官方给出了三种解决方案:

  1. 使用 class fields.
  2. 在回调中使用箭头函数
  3. 在构造函数中使用bind绑定this

案例一==>class fields:

  1. class LoggingButton extends React.Component {
  2. // 此语法确保 `handleClick` 内的 `this` 已被绑定。
  3. // 注意: 这是 *实验性* 语法。
  4. handleClick = () => {
  5. console.log('this is:', this);
  6. }
  7. render() {
  8. return (
  9. <button onClick={this.handleClick}>
  10. Click me
  11. </button>
  12. );
  13. }
  14. }

案例二==>回调中使用箭头函数

  1. class LoggingButton extends React.Component {
  2. handleClick() {
  3. console.log('this is:', this);
  4. }
  5. render() {
  6. // 此语法确保 `handleClick` 内的 `this` 已被绑定。
  7. return (
  8. <button onClick={() => this.handleClick()}>
  9. Click me
  10. </button>
  11. );
  12. }
  13. }

但是这种方法存在某些问题:

此语法问题在于每次渲染 LoggingButton 时都会创建不同的回调函数。在大多数情况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题。

案例三==>构造器中绑定 :

  1. class Toggle extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {isToggleOn: true};
  5. // 为了在回调中使用 `this`,这个绑定是必不可少的
  6. this.handleClick = this.handleClick.bind(this);
  7. }
  8. handleClick() {
  9. this.setState(state => ({
  10. isToggleOn: !state.isToggleOn
  11. }));
  12. }
  13. render() {
  14. return (
  15. <button onClick={this.handleClick}>
  16. {this.state.isToggleOn ? 'ON' : 'OFF'}
  17. </button>
  18. );
  19. }
  20. }
  21. ReactDOM.render(
  22. <Toggle />,
  23. document.getElementById('root')
  24. );

规定一种写法:构造器中绑定。

向事件处理程序传递参数

在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:

  1. <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
  2. <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

上述两种方式是等价的,分别通过箭头函数Function.prototype.bind 来实现。

在这两种情况下,React 的事件对象 e 会被作为第二个参数传递。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

列表&key

一个好的经验法则是:在 map() 方法中的元素需要设置 key 属性。

refs&DOM

ref的三种方式:

  1. //官方文档版
  2. class Reftest extends React.Component{
  3. constructor(props){
  4. super(props)
  5. this.handClick = this.handClick.bind(this)
  6. this.input = React.createRef()
  7. }
  8. handClick(){
  9. alert(this.input.current.value)
  10. }
  11. render(){
  12. return(
  13. <div>
  14. <input ref={this.input}/>
  15. <button onClick={this.handClick}>点我</button>
  16. </div>
  17. )
  18. }
  19. }
  20. ReactDOM.render(<Reftest/> , document.getElementById('root'))
  1. //网课版
  2. class Reftest extends React.Component{
  3. constructor(props){
  4. super(props)
  5. this.handClick = this.handClick.bind(this)
  6. }
  7. handClick(){
  8. alert(this.input.value)
  9. }
  10. render(){
  11. return(
  12. <div>
  13. <input ref={input=>this.input = input}/>
  14. <button onClick={this.handClick}>点我</button>
  15. </div>
  16. )
  17. }
  18. }
  19. ReactDOM.render(<Reftest/> , document.getElementById('root'))
  1. //老版本
  2. class Reftest extends React.Component{
  3. constructor(props){
  4. super(props)
  5. this.handClick = this.handClick.bind(this)
  6. this.input = React.createRef()
  7. }
  8. handClick(){
  9. alert(this.refs.input.value)
  10. }
  11. render(){
  12. return(
  13. <div>
  14. <input ref='input'/>
  15. <button onClick={this.handClick}>点我</button>
  16. </div>
  17. )
  18. }
  19. }
  20. ReactDOM.render(<Reftest/> , document.getElementById('root'))

React-router 基本使用

安装

  1. npm install react-router-dom --save

组件

BrowserRouter
HashRouter
Rout
Redirect
Link
NavLink
Switch

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. import {BrowserRouter, HashRouter} from 'react-router-dom'
  4. import App from './components/app'
  5. import './index.css'
  6. ReactDOM.render(
  7. (
  8. <BrowserRouter>
  9. <App/>
  10. </BrowserRouter>
  11. /*<HashRouter>
  12. <App />
  13. </HashRouter>*/
  14. ),
  15. document.getElementById('root')
  16. )
  1. import React from 'react'
  2. import {Route, Switch, Redirect} from 'react-router-dom'
  3. import MyNavLink from './my-nav-link'
  4. import About from '../views/about'
  5. import Home from '../views/home'
  6. export default class App extends React.Component {
  7. render() {
  8. return (
  9. <div>
  10. <div className="row">
  11. <div className="col-xs-offset-2 col-xs-8">
  12. <div className="page-header">
  13. <h2>React Router Demo</h2>
  14. </div>
  15. </div>
  16. </div>
  17. <div className="row">
  18. <div className="col-xs-2 col-xs-offset-2">
  19. <div className="list-group">
  20. {/*导航路由链接*/}
  21. <MyNavLink className="list-group-item" to='/about'>About</MyNavLink>
  22. <MyNavLink className="list-group-item" to='/home'>Home</MyNavLink>
  23. </div>
  24. </div>
  25. <div className="col-xs-6">
  26. <div className="panel">
  27. <div className="panel-body">
  28. {/*可切换的路由组件*/}
  29. <Switch>
  30. <Route path='/about' component={About}/>
  31. <Route path='/home' component={Home}/>
  32. <Redirect to='/about'/>
  33. </Switch>
  34. </div>
  35. </div>
  36. </div>
  37. </div>
  38. </div>
  39. )
  40. }
  41. }

React-redux 基本使用

安装

1.安装redux和react-redux

  1. npm install react-redux redux --save

2.使用chrome调试工具

chrome应用商店搜索redux 安装插件

  1. npm install redux-devtools-extension -S -D

3.项目中使用redux先创建目录文件夹.

React笔记 - 图1

4.文件内容

store.js

  1. // import React from 'react'
  2. import {createStore,applyMiddleware} from 'redux'
  3. import thunk from 'redux-thunk'
  4. import {composeWithDevTools} from 'redux-devtools-extension'
  5. import reducers from './reducers'
  6. // 根据counter函数创建store对象
  7. export default createStore(
  8. reducers,
  9. composeWithDevTools(applyMiddleware(thunk)) // 应用上异步中间件
  10. )

在该文件中引入redux-thunk

默认的redux是无法进行异步操作的,只能进行同步操作。

redux-thunk是一个可以让redux可以进行异步编程的redux插件

createStore():作用是创建包含指定 reducerstore 对象

applyMiddleware():作用应用上基于 redux 的中间件(插件库)

reducers.JS

  1. import {combineReducers} from 'redux'
  2. import {ADD_TODO_LIST,REMOVE_TODO_LIST,ADD_REMOVE_LIST} from './action-types'
  3. function todoList(state = [] ,action){
  4. switch (action.type){
  5. case ADD_TODO_LIST:
  6. let list = state
  7. list.push(action.item)
  8. return list
  9. case REMOVE_TODO_LIST:
  10. return state.filter((item,index)=>index!==action.item)
  11. default:
  12. return state
  13. }
  14. }
  15. function removeList(state = [] ,action){
  16. switch (action.type){
  17. case ADD_REMOVE_LIST:
  18. let list = state
  19. list.push(action.item)
  20. return list
  21. default:
  22. return state
  23. }
  24. }
  25. export default combineReducers({
  26. todoList,
  27. removeList
  28. })

combineReducers():作用是合并多个 reducer 函数

actions.js

  1. import {ADD_TODO_LIST,REMOVE_TODO_LIST,ADD_REMOVE_LIST} from './action-types'
  2. export const addTodoList = item => ({type:ADD_TODO_LIST,item})
  3. export const removeTodoList = item => ({type:REMOVE_TODO_LIST,item})
  4. export const addRemoveList = item => ({type:ADD_REMOVE_LIST,item})

异步的操作:(前提是在storejs中配置了redux-thunk)

  1. // 异步action creator(返回一个函数)
  2. export const addTodoListAsync = item => {
  3. return dispatch => {
  4. setTimeout(() => {
  5. dispatch(addTodoList(item))
  6. }, 1000)
  7. }
  8. }

action-types.js

  1. export const ADD_TODO_LIST = 'ADD_TODO_LIST'
  2. export const REMOVE_TODO_LIST = 'REMOVE_TODO_LIST'
  3. export const ADD_REMOVE_LIST = 'ADD_REMOVE_LIST'

index.js

  1. import React from 'react'
  2. import ReactDOM from 'react-dom';
  3. import {BrowserRouter} from 'react-router-dom'
  4. import {Provider} from 'react-redux';
  5. import App from './components/app/app'
  6. import store from './redux/store';
  7. ReactDOM.render((
  8. <BrowserRouter>
  9. <Provider store={store}>
  10. <App/>
  11. </Provider>
  12. </BrowserRouter>
  13. ),document.getElementById('root'))

到此为止,在react中使用redux的配置就算好了。

5.react-redux的介绍

react-redux是一个react 插件库,专门用来简化 react 应用中使用 redux 。

React-Redux 将所有组件分成两大类

UI组件

  1. 专门负责 UI 的呈现,不带有任何业务逻辑。
  2. 通过props接受redux里的属性和方法。
  3. 且不使用任何 Redux 的 API。
  4. 一般保存在 components 文件夹下

容器组件

  1. 负责管理数据和业务逻辑,不负责 UI 的呈现
  2. 使用 Redux 的 API
  3. 一般保存在 containers 文件夹下

相关API

Provider:让所有组件都可以得到 state 数据

connect:用于包装 UI 组件生成容器组件

mapStateToprops:将外部的数据(即 state 对象)转换为 UI 组件的标签属性

mapDispatchToProps:将分发 action 的函数转换为 UI 组件的标签属性 简洁语法可以直接指定为 actions 对象或包含多个 action 方法的对象

React笔记 - 图2

通过容器组件将UI组件包装在内,这样UI组件就可以通过props接收redux的属性和方法。

在引入组件的时候,需要引入容器组件。React笔记 - 图3

UI组件引入props就行了

React笔记 - 图4