美文网首页
React Hooks demo

React Hooks demo

作者: Joemoninni | 来源:发表于2020-10-10 16:40 被阅读0次

    react hooks demo

    1. 创建所需要的组件,这个项目我们分成三个组件, 分别是头部,搜索框,电影列表

      // Header.js
      import React from 'react'
      export default function Header(props) {
       return (
           <div>
               <header className="app_header">
                   <h2>{props.text}</h2>
                  </header>
              </div>
          )    
      }
      
      // Movie.js
      import React from 'react'
      
      const DEFAULT_PLACEHOLDER_IMAGE = 'https://m.media-amazon.com/images/M/MV5BMTczNTI2ODUwOF5BMl5BanBnXkFtZTcwMTU0NTIzMw@@._V1_SX300.jpg'
      
      export default function Movie({movie}) {
          const poster = movie.Poster = 'N/A' ? DEFAULT_PLACEHOLDER_IMAGE : movie.Poster
          return (f
           <div className="movie">
               <h2>{movie.Title}</h2>
                  <div>
                   <img width="200" src={poster} alt={`The Movie Titled: ${movie.Title}`} />
                  </div> 
              </div>
          )
      }
      
      // Search.js
      import React, { useState } from 'react'
      
      export default function Search(props) {
          const [searchValue, setSearchValue] = useState('')
          
          const handleSearchInputChanges = (e) => {
              setSearchValue(e.target.value)
          }
          const resetInputField = () => {
              setSearchValue('')
          }
          const handleInputSearch = (e) => {
              e.preventDefault()
              props.search(searchValue)
              resetInputField()
          }
          
          return (
           <div>
               <form className="search">
                   <input type="text" onChange={handleSearchInputChanges} value={searchValue}  />
                      <input type="submit" onClick={handleInputSearch} value="SEARCH" />
                  </form>
              </div>
          )
      }
      
    2. 创建App.js

      // App.js
      import React, { useState, useEffect } from 'react'
      import Header from './Header.js'
      import Movie from './Movie.js'
      import Search from './Search.js'
      import axios from 'axios'
      
      const MOVIE_API_URL = 'https://www.omdbapi.com/?s=man&apikey=62b53dxx'
      
      export default function App() {
          const [loading, setLoading] = useState(true)
          const [movie, setMovie] = useState([])
          const [errorMessage, setErrorMessage] = useState(null)
          /**
          这里我们使用了三个useState函数,所以在一个组件中可以有多个useState函数
          1. loading: 用于处理加载状态,加载时页面呈现一个Loading
          2. movie: 用于处理从服务器获取的movies数组/数据
          3. errorMessage: 用于处理在发出API请求时可能发生的任何错误
          */
          
          const search = (searchVal) => {
              setLoading(false)
              setErrorMessage(null)
              axios.get(`https://www.omdbapi.com/?s=${searchVal}&apikey=62b53dxx`).then(res => {
                  if (res.data.Response === 'True') {
                      setMovie(res.data.Search)
                  } else {
                      setErrorMessage(res.data.Error)
                  }
                  setLoading(false)
              })
          }
          
          useEffect(() => {
              axios.get(MOVIE_API_URL).then(res => {
                  setMovie(res.data.Search)
                  setLoading(false)
              })
          }, [])
          /**
          这里使用了useEffect,这个Hooks可以让你在函数式组件中执行副作用, 所谓的副作用是指数据获取,订阅和手动操作DOM
          我们也可以将useEffect看作是componentDidMount, componentDidUpdate和componentWillUnmount的组合(这是因为在组件第一次render之后(componentDidMount)和每次组件更新之后(componentDidUpdate), useEffect都会被调用)
          */
          
          return (
           <div className="App">
               <Header text={Movies Demo} />
                  <Search search={search} />
                  <div className="movies">
                      {
                          loading && !errorMessage ? (<span>loading...</span>)   : 
                           errorMessage            ? (<div>{errorMessage}</div>) : 
                          (movie.map((item, index) => {<Movie key={`${index}-${movie.Title}`} movie={item} />}))
                      }
                  </div>
              </div>
          )
      }
      

      如果项目中需要定义多个状态,那我们使用useState会显得代码比较冗余,也比较乱,建议用useReducer,统一管理下代码。我们修改App.js文件如下:

      import React, { useReducer } from 'react'
      import Header from './Header'
      import Movie from './Movie'
      import Search from './Search'
      import axios from 'axios'
      
      const initialState = {
          loading: true,
          movie: [],
           errorMessage: null
      }
      
      const reducer = (state, action) => {
          switch(action.type) {
              case 'SEARCH_MOVIE_REQUEST':
                  return {
                      ...state,
                      loading: true,
                      errorMessage: null
                  } 
              case "SEARCH_MOVIE_SUCCESS":
                  return {
                      ...state,
                      loading: false,
                      movie: action.payload
                  }
              case 'SEARCH_MOVIE_FAILURE': 
                  return {
                      ...state,
                      loading: false,
                      errorMessage: action.error
                  }
              default: 
                  return state
          }
      }
      
      export default App() {
          const [state, dispatch] = useReducer(reducer, initialState)
          
          const { loading, movie, errorMessage } = state
          
          const search = (searchVal) => {
              // setLoading(false)
              // setErrorMessage(null)
              // 修改为:
              dispatch({
                  type: 'SEARCH_MOVIE_REQUEST'
              })
              
              axios.get(`https://www.omdbapi.com/?s=${searchVal}&apikey=62b53dxx`).then(res => {
                  if (res.data.Response === 'True') {
                      // setMovie(res.data.Search)
                      // 修改为:
                      dispatch({
                          type: 'SEARCH_MOVIE_SUCCESS',
                          payload: res.data.Search
                      })
                  } else {
                      // setErrorMessage(res.data.Error)
                      // 修改为:
                      dispatch({
                          type: 'SEARCH_MOVIE_FAILURE',
                          error: res.data.Error
                      })
                  }
                  // setLoading(false)
              })
          }
          
          useEffect(() => {
              axios.get(MOVIE_API_URL).then(res => {
                  // setMovie(res.data.Search)
                  // setLoading(false)
                  // 修改为:
                  dispatch({
                      type: 'SEARCH_MOVIE_SUCCESS',
                      payload: res.data.Search
                  })
              })
          }, [])
          
           return (
           <div className="App">
               <Header text={Movies Demo} />
                  <Search search={search} />
                  <div className="movies">
                      {
                          loading && !errorMessage ? (<span>loading...</span>)   : 
                           errorMessage            ? (<div>{errorMessage}</div>) : 
                          (movie.map((item, index) => {<Movie key={`${index}-${movie.Title}`} movie={item} />}))
                      }
                  </div>
              </div>
          )
      }
      

      这样好像看起来还是代码有点多,而且全部都写在App.js这个文件中, 我们可以把state和reducer拆分到另外的文件,然后再引入

      我们在src目录下新建一个store文件夹,store目录下再建一个reducer文件夹

      //  src/store/reducer/index.js
      
      export const initialState = {
          loading: true,
          movie: [],
          errorMessage: null
      }
      
      export const reducer = (state, action) => {
          switch(action.type) {
                  case: 'SEARCH_MOVIE_REQUSET': 
                   return {    
                          ...state, 
                          loading: false,
                          errorMessage: null
                      }
                  case: 'SEARCH_MOVIE_SUCCESS':
                   return {
                          ...state, 
                          loading: true,
                          movie: action.payload
                      }
                  case: 'SEARCH_MOVIE_FAILURE': 
                   return {
                          ...state, 
                          loading: true,
                          errorMessage: action.error
                      }
              default: 
                  return state
          }
      }
      

      App.js中引入,然后就可以使用我们自定义的state和reducer了

      import { initialState, reducer } from '../store/reducer'
      

    相关文章

      网友评论

          本文标题:React Hooks demo

          本文链接:https://www.haomeiwen.com/subject/dbzlpktx.html