• 05-React组件的组合使用


    05-React组件的组合使用


    1.TodoList案例

    需求:TodoList组件化实现此功能

    1. 显示所有todo列表
    2. 输入文本, 点击按钮显示到列表的首位, 并清除输入的文本

    1).实现:

    1. 完成TodoList组件的静态页面以及拆解组件

    2. 动态初始化列表

      //App.jsx
      export default class App extends Component {
        // 初始化状态
        state = {
          todos: [
            { id: '001', name: '吃饭', done: true },
            { id: '002', name: '睡觉', done: true },
            { id: '003', name: '敲代码', done: false },
            { id: '004', name: '逛街', done: true },
          ]
        }
        render() {
          const { todos } = this.state
          return (
            
      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      //List.jsx
      export default class List extends Component {
        render() {
         // 接收来自App父组件传递的数据   
          const { todos } = this.props
          return (
            
        {todos.map(todo => { return })}
      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      //Item.jsx
      export default class Item extends Component {
        render() {
            // 接收来自List父组件传递的数据   
          const { id, name, done } = this.props
          return (
            
    3. ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

    4. 完成添加“任务”的功能(父子组件之间传值)

      父组件中创建一个添加数据的方法addTodo,然后将方法传递给子组件,当子组件向该方法传递了参数后,父组件便可以接收到子组件传递的参数

      //App.jsx
      export default class App extends Component {
        // 初始化状态
        state = {
          todos: [
            { id: '001', name: '吃饭', done: true },
            { id: '002', name: '睡觉', done: true },
            { id: '003', name: '敲代码', done: false },
            { id: '004', name: '逛街', done: true },
          ]
        }
       //addTodo用于添加一个todo,接收的参数是todo对象
        addTodo = (todoObj) => {
          console.log('APP:' + data);
          // 获取原数组
          const { todos } = this.state
          // 追加一个新数组
          const newTodos = [todoObj, ...todos]
          // 更新状态
          this.setState({ todos: newTodos })
        }   
        render() {
          const { todos } = this.state
          return (
            
      ) } }
      • 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

      子组件Header创建一个点击回车键回调的方法handlerKeyUp,在该方法中向从父组件接收到的方法addTodo中传递参数,将新添加的数据反馈给父组件

      //Header.jsx
      export default class Header extends Component {
        // 键盘事件的回调
        handlerKeyUp = (event) => {
          // keyCode 触发事件的按键码
          // 解构赋值keyCode, target
          const { keyCode, target } = event
          // 判断是否是回车按键
          if (keyCode !== 13) return
          // 添加的todo名字不能为空
          if (target.value.trim() == '') {
            alert('输入不能为空')
            return
          }
          // 准备一个新的todo对象
          const todoObj = {
           // 使用nanoid库创建一个不重复的ID   
            id: nanoid(),
            name: target.value,
            done: false
          }
          this.props.addTodo(todoObj);
          // 清空输入
          target.value='';
        }
        render() {
          return (
            
      ) } }
      • 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

    5. 完成删除"任务"的功能(祖孙组件之间的传值)

      在祖组件中创建一个删除数据的方法deleteTodo,然后将方法传递给子组件,再由子组件传递给孙组件,当孙组件向该方法传递了参数后,祖组件便可以接收到子组件传递的参数

      //App.jsx
      export default class App extends Component {
        // 初始化状态
        state = {
          todos: [
            { id: '001', name: '吃饭', done: true },
            { id: '002', name: '睡觉', done: true },
            { id: '003', name: '敲代码', done: false },
            { id: '004', name: '逛街', done: true },
          ]
        }
        // deleteTodo用于删除一个todo对象
        deleteTodo = (id) => {
          const { todos } = this.state
          // 删除指定id的todo对象
          const newTodos = todos.filter(todoObj => {
            return todoObj.id !== id
          })
          // 更新状态
          this.setState({ todos: newTodos })
        }
        render() {
          const { todos } = this.state
          return (
            
      ) } }
      • 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

      List组件接收从父组件传递来的删除数据的方法deleteTodo,再将deleteTodo方法传递给自己的子组件Item

      //List.jsx
      export default class List extends Component {
        render() {
          const { todos, updateTodo} = this.props
          return (
            
        {todos.map(todo => { return })}
      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      Item组件创建一个删除“任务”的回调方法handleDelete,然后在该方法中调用deleteTodof方法,将需要删除的数据id传递给祖组件App

      //Item.jsx
      export default class Item extends Component {
        // 删除一个todo的回调
        handleDelete = (id) => {
          // console.log('通知App删除'+id);
          if (window.confirm('确定删除吗?')) {
            this.props.deleteTodo(id)
          }
        }
        render() {
          const { id, name, done } = this.props
          const { mouse } = this.state
          return (
            
    6. { backgroundColor: mouse ? '#ddd' : 'white' }} onMouseLeave={this.handleMouse(false)} onMouseEnter={this.handleMouse(true)}>
    7. ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23

    8. 为每个Item组件添加鼠标移入高亮且删除按钮显现、鼠标移出无高亮显示且删除按钮隐藏的效果

      //Item.jsx
      export default class Item extends Component {
          state = {
              mouse: false //标识鼠标移入、移出
          }
          //鼠标移入、移出的回调
          handleMouse = (flag) => {
              return () => {
                  this.setState({ mouse: flag })
              }
          }
          // 删除一个todo的回调
          handleDelete = (id) => {
              if (window.confirm('确定删除吗?')) {
                  this.props.deleteTodo(id)
              }
          }
          render() {
              const { id, name, done } = this.props
              const { mouse } = this.state
              return (
                  
    9. { backgroundColor: mouse ? '#ddd' : 'white' }} onMouseLeave={this.handleMouse(false)} onMouseEnter={this.handleMouse(true)}>
    10. ) } }
      • 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

    11. 修改Item组件勾选框的状态和修改数据(祖孙组件之间的传值)

      在祖组件中创建一个更新数据的方法updateTodo,然后将方法传递给子组件,再由子组件传递给孙组件,当孙组件向该方法传递了参数后,祖组件便可以接收到子组件传递的参数

      //App.jsx
      export default class App extends Component {
        // 初始化状态
        state = {
          todos: [
            { id: '001', name: '吃饭', done: true },
            { id: '002', name: '睡觉', done: true },
            { id: '003', name: '敲代码', done: false },
            { id: '004', name: '逛街', done: true },
          ]
        }
        // updateTodo用于更新一个todo对象
        updateTodo = (id, done) => {
          // 获取状态中的todos
          const { todos } = this.state
          // 匹配处理数据
          const newTodos = todos.map(todoObj => {
            if (todoObj.id === id) return { ...todoObj, done }
            else return todoObj
          })
          this.setState({ todos: newTodos })
        }
        render() {
          const { todos } = this.state
          return (
            
      ) } }
      • 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

      List组件接收从父组件传递来的删除数据的方法updateTodo,再将updateTodo方法传递给自己的子组件Item

      //List.jsx
      export default class List extends Component {
        render() {
          const { todos, updateTodo, deleteTodo } = this.props
          return (
            
        {todos.map(todo => { return })}
      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      Item组件创建一个更新数据的回调方法handleDelete,然后在该方法中调用updateTodo方法,将需要更新的数据id传递给祖组件App

      export default class Item extends Component {
          state = {
              mouse: false //标识鼠标移入、移出
          }
          //鼠标移入、移出的回调
          handleMouse = (flag) => {
              return () => {
                  this.setState({ mouse: flag })
                  // console.log(flag);
              }
          }
          //勾选、取消勾选某一个todo的回调
          handleChange = (id) => {
              return (event) => {
                  // console.log(id,event.target.checked);
                  this.props.updateTodo(id, event.target.checked);
              }
          }
          // 删除一个todo的回调
          handleDelete = (id) => {
              // console.log('通知App删除'+id);
              if (window.confirm('确定删除吗?')) {
                  this.props.deleteTodo(id)
              }
          }
          render() {
              const { id, name, done } = this.props
              const { mouse } = this.state
              return (
                  
    12. { backgroundColor: mouse ? '#ddd' : 'white' }} onMouseLeave={this.handleMouse(false)} onMouseEnter={this.handleMouse(true)}>
    13. ) } }
      • 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

    14. 完成底部组件全选修改数据的功能

      //APP.jsx
      export default class App extends Component {
          // 初始化状态
          state = {
              todos: [
                  { id: '001', name: '吃饭', done: true },
                  { id: '002', name: '睡觉', done: true },
                  { id: '003', name: '敲代码', done: false },
                  { id: '004', name: '逛街', done: true },
              ]
          }
          // checkAllTodo用于全选
          checkAllTodo=(done)=>{
              // 获取原来的todos
              const {todos}=this.state
              // 处理数据
              const newTodos=todos.map(todoObj=>{
                  return {...todoObj,done}
              })
              // 更新数据
              this.setState({todos:newTodos})
          }
          render() {
              const { todos } = this.state
              return (
                  
      ) } }
      • 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
      //Footer.jsx
      export default class Footer extends Component {
        handleChange=(event)=>{
          this.props.checkAllTodo(event.target.checked)
        }
        render() {
          const {todos}=this.props
          // 已完成的个数
          const doneCount=todos.reduce((pre,todo)=>pre+(todo.done?1:0),0)
          // 总数
          const total=todos.length
          return (
            
      已完成{doneCount} / 全部{total}
      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24

    15. 完成“清楚已完成任务”按钮的功能

      export default class App extends Component {
        // 初始化状态
        state = {
          todos: [
            { id: '001', name: '吃饭', done: true },
            { id: '002', name: '睡觉', done: true },
            { id: '003', name: '敲代码', done: false },
            { id: '004', name: '逛街', done: true },
          ]
        }
        // clearAllDone用于清除所有已完成的
        clearAllDone=()=>{
          // 获取原来的todos
          const {todos}=this.state
          // 处理数据
          const newTodos= todos.filter(todoObj=>{
            return !todoObj.done
          })
          // 更新状态
          this.setState({todos:newTodos})
        }
        render() {
          const { todos } = this.state
          return (
            
      ) } }
      • 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
      export default class Footer extends Component {
        handleClearAllDone=()=>{
          this.props.clearAllDone()
        }
        render() {
          const {todos}=this.props
          // 已完成的个数
          const doneCount=todos.reduce((pre,todo)=>pre+(todo.done?1:0),0)
          // 总数
          const total=todos.length
          return (
            
      已完成{doneCount} / 全部{total}
      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23

    2).总结:

    todoList案例相关知识点:

    1. 拆分组件、实现静态组件,注意:className、style的写法
    2. 动态初始化列表,如何确定将数据放在哪个组件的state中?
      1. 某个组件使用:放在其自身的state中
      2. 某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)
    3. 关于父子之间通信:
      1. 【父组件】给【子组件】传递数据:通过props传递
      2. 【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数
    4. 注意defaultChecked和checked的区别,类似的还有:defaultValue和value
    5. 状态在哪里,操作状态的方法就在哪里

    2.GitHub搜索案例

    效果:

    1).实现:

    a.使用axios发送请求
    1. 搭建组件静态效果

      //List.jsx
      export default class List extends Component {
          render() {
              return (
                  

      {user.login}

      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      //Search.jsx
      export default class Search extends Component {
        render() {
          return (
            

      搜索Github用户

       
      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    2. 配置脚手架代理(配置代理

      const { createProxyMiddleware } = require('http-proxy-middleware');
      module.exports = function (app) {
          app.use(
              createProxyMiddleware('/api1', {    
                  target: 'http://localhost:5000',   
                  secure: false,  //
                  changeOrigin: true,    
                  pathRewrite: {
                      '^/api1': '',
                  },  
              })
          )
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    3. 完成搜索框的搜索和发送请求的功能

      1. 收集Search组件输入框的内容

        export default class Search extends Component {
            Search = () => {
                // 连续解构赋值+重命名
                const { KeyWordElement: { value: keyWord } } = this;
                console.log(keyWord);
            }
            render() {
                return (
                    

        搜索Github用户

        this.KeyWordElement = c} type="text" placeholder="输入关键词点击搜索" /> 
        ) } }
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18

      2. 发送请求

        export default class Search extends Component {
            Search = () => {
                const { KeyWordElement: { value: keyWord } } = this;
                // 发送请求
                axios.get(`/api1/search/users2?q=${keyWord}`).then(
                    response => { 
                        console.log(response.data.items);
                    },
                    error => { 
                        console.log('失败了', error); 
                    }
                )
            }
            render() {
                return (
                    

        搜索Github用户

        this.KeyWordElement = c} type="text" placeholder="输入关键词点击搜索" /> 
        ) } }
        • 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

    4. 动态初始化组件的状态

      //App.jsx
      export default class App extends Component {
          // 初始化状态
          state={
              users:[],//users初始值为数组
              isFirst:true,//是否为第一次打开页面
              isLoading:false,//标识是否处于加载中
              err:""// 存储请求相关的错误信息
          }
          render() {
              const {users}=this.state
              return (
                  
      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      //List.jsx
      export default class List extends Component {
          render() {
              const { users,isFirst,isLoading,err } = this.props
              return (
                  
      { //使用三元运算符动态显示组件的内容 isFirst?

      欢迎使用,输入关键字,随后点击搜索

      : isLoading?

      Loading......

      : err?

      {color:'red'}}>{err}

      : users.map(user => { return ( ) }) }
      ) } }
      • 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
    5. 发起请求并将数据显示到组件上

      //App.jsx
      export default class App extends Component {
          // 初始化状态
          state={
              users:[],//users初始值为数组
              isFirst:true,//是否为第一次打开页面
              isLoading:false,//标识是否处于加载中
              err:""// 存储请求相关的错误信息
          }
          // 更新App的state
          updateAppState=(stateObj)=>{
              this.setState(stateObj)
          }
          render() {
              const {users}=this.state
              return (
                  
      ) } }
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      //Search.jsx
      export default class Search extends Component {
        Search = () => {
          // 连续解构赋值+重命名
          const { KeyWordElement: { value: keyWord } } = this;
          //  发送请求前通知App更新状态
          this.props.updateAppState({ isFirst:false,isLoading:true,})
          // 发送请求
          axios.get(`/api1/search/users2?q=${keyWord}`).then(
            response => { 
              //请求成功后通知App更新状态
              this.props.updateAppState({isLoading:false,users:response.data.items})
            },
            error => { 
              console.log('失败了', error); 
              // 请求成功后通知App更新状态
              this.props.updateAppState({isLoading:false,err:error.message})
            }
          )
        }
        render() {
          return (
            

      搜索Github用户

      this.KeyWordElement = c} type="text" placeholder="输入关键词点击搜索" /> 
      ) } }
      • 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
    b.使用PubSub实现(兄弟组件之间传值)

    消息订阅-发布机制

    1. 工具库: PubSubJS

    2. 下载:

      npm install pubsub-js --save
      
      • 1
    3. 使用:

      1. import PubSub from 'pubsub-js' //引入
        
        • 1
      2. PubSub.subscribe('delete', function(data){ }); //订阅
        
        • 1
      3. PubSub.publish('delete', data) //发布消息
        
        • 1
      4. PubSub.unsubscribe(this.xxx)
        
        • 1
    4. 初始化各个组件

      //App.jsx
      export default class App extends Component {
          render() {
              return (
                  
      ) } } //Search.jsx export default class Search extends Component { render() { return (

      搜索Github用户

       
      ) } } //List.jsx export default class List extends Component { render() { return (

      {user.login}

      ) } }
      • 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
    5. 初始化组件的状态

      //List.jsx
      export default class List extends Component {
        // 初始化状态
        state = {
          users: [],
          isFirst: true,
          isLoading: false,
          err: ""
        }
        render() {
          const { users, isFirst, isLoading, err } = this.state
          return (
            
      { isFirst ?

      欢迎使用,输入关键字,随后点击搜索

      : isLoading ?

      Loading......

      : err ?

      { color: 'red' }}>{err}

      : users.map(user => { return ( ) }) }
      ) } }
      • 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
    6. 发布消息与发送请求数据

      //Search.jsx
      export default class Search extends Component {
        Search = () => {
          const { KeyWordElement: { value: keyWord } } = this;
          PubSub.publish('Spongebob',{isFirst:false,isLoading:true})
          axios.get(`/api1/search/users2?q=${keyWord}`).then(
            response => { 
              PubSub.publish('Spongebob',{isLoading:false,users:response.data.items})
            },
            error => { 
              PubSub.publish('Spongebob',{isLoading:false,err:error.message})
            }
          )
        }
        render() {
          return (
            

      搜索Github用户

      this.KeyWordElement = c} type="text" placeholder="输入关键词点击搜索" /> 
      ) } }
      • 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
    7. 订阅消息与动态更新数据

      export default class List extends Component {
        // 初始化状态
        state = {
          users: [],
          isFirst: true,
          isLoading: false,
          err: ""
        }
        componentDidMount() {
          this.token = PubSub.subscribe('Spongebob', (_, stateObj) => {
            this.setState(stateObj)
          })
        }
        componentWillUnmount() {
         // 组件销毁后取消订阅消息   
          PubSub.unsubscribe(this.token)
        }
        render() {
          const { users, isFirst, isLoading, err } = this.state
          return (
            
      { isFirst ?

      欢迎使用,输入关键字,随后点击搜索

      : isLoading ?

      Loading......

      : err ?

      { color: 'red' }}>{err}

      : users.map(user => { return ( ) }) }
      ) } }
      • 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
    c.使用fetch发送请求

    Fetch

    特点:

    1. fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求
    2. 老版本浏览器可能不支持
    export default class Search extends Component {
        Search = async() => {
            const { KeyWordElement: { value: keyWord } } = this;
            PubSub.publish('Spongebob',{isFirst:false,isLoading:true})
            // 发送请求
            try {
                const response=await fetch(`/api1/search/users2?q=${keyWord}`);
                PubSub.publish('Spongebob',{isFirst:false,isLoading:true})
                const result=await response.json();
                // PubSub.publish('Spongebob',{isLoading:false,users:result})
                console.log(result);
            } catch (error) {
                console.log('请求出错',error);
            }
        }
        render() {
            return (
                

    搜索Github用户

    this.KeyWordElement = c} type="text" placeholder="输入关键词点击搜索" /> 
    ) } }
    • 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

    2).总结:

    github搜索案例相关知识点:

    1. 设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办。

    2. ES6小知识点:解构赋值+重命名

      let obj {a:{b:1}}
      //传统解构赋值
      const{a}=obj;
      //连续解构赋值
      const{a:(b}}=obj;
      //连续解构赋值+重命名
      const{a:{b:value}}=obj;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    3. 消息订阅与发布机制

      1. 先订阅,再发布(理解:有一种隔空对话的感觉)
      2. 适用于任意组件间通信
      3. 要在组件的componentwillUnmount中取消订阅
    4. fetch发送请求(关注分离的设计思想)

      try{
          const response=await fetch(/api1/search/users2?q=${keyWord))
          const data await response.json()
          console.log(data);
      }catch (error){
          console.1og('请求出错',error);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
  • 相关阅读:
    [C++] 哈希的模拟实现---闭散列法、开散列法(上)
    算法竞赛进阶指南 基本算法 0x04 二分与三分
    1422. 分割字符串的最大得分
    1.1 计算机组成原理----概述
    云效平台是做什么的?有哪些优缺点?
    态路小课堂丨光纤跳线的使用与维护小指南
    云计算中的负载均衡技术,确保资源的平衡分配
    conda 克隆/复制 虚拟环境
    美团隐私计算平台通过行业权威认证
    CleanMyMac X专业清理软件更新 助力M2芯Mac保持最佳状态
  • 原文地址:https://blog.csdn.net/m0_57262196/article/details/133844687