react---大总结大复习

别人的总结

React

React 是 facebook 出的一款针对前端 view 视图层的 library 库。react 使用了 jsx 语法(就是在 js 中写 html 标签)

https://zh-hans.reactjs.org/ react 官网地址

7/27 第一天

react js 文件的引入

<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<!-- js文件引入的顺序,先引入react.js,再引入react-dom.js -->
<script src="./libs/react.js"></script>
<script src="./libs/react-dom.js"></script>
<!-- <script src="./db.js"></script> -->
<!-- script标签必须加上type="text/babel",因为我们需要解析jsx语法 -->
<script type="text/babel">
  // var list = [];
  // console.log(pets);
  // 在react中组件需要使用大写开头
  // react传参使用props
  function HelloWorld(props) {
    return <h1>你好,世界!,count值为:{props.count}</h1>
  }

  // 使用了class类的继承
  class HelloMesage extends React.Component {
    // render表示渲染组件,所有的组件中都有这个方法
    render() {
      return <h5>我是一句话</h5>
    }
  }
  // render 参数一 表示展示的组件内容,参数二表示位置
  // react 中花括号 {} 里面是js表达式
  ReactDOM.render(<HelloMesage count={2} />, document.getElementById('app'))
</script>

第一个 react 循环数据

// React中所有的组件都是一个function对象
      function Person(props) {
        // 在react中设置样式的时候使用style
        // 在react中设置class样式名的时候需要写成className,因为class是js的保留字
        return (
          <li className="person" style={{ color: props.color }}>
            {props.name}
          </li>
        );
      }

      function People() {
        const renwu = ["Tom", "Jerry", "马冬梅"];
        // 使用jsx循环生成数据的时候一定要使用map
        return (
          <ul>
            {renwu.map((p, i) => (
              <Person key={i} color={i % 2 == 0 ? "red" : "blue"} name={p} />
            ))}
          </ul>
        );
      }
      // render 参数一 表示展示的组件内容,参数二表示位置
      ReactDOM.render(<People />, document.getElementById("app"));
    </script>
// 请求接口渲染数据
// fetch原生js自带的一种http数据请求方式
fetch('http://localhost:3009/api/v1/products')
  .then((res) => res.json())
  .then((res) => {
    function Products() {
      //使用jsx循环生成数据的时候一定要使用map
      return (
        <ul>
          {res.products.map((p, i) => (
            <li key={p._id}>{p.name}</li>
          ))}
        </ul>
      )
    }
    //render 参数一 表示展示的组件内容,参数二表示位置
    ReactDOM.render(<Products />, document.getElementById('app'))
  })

7/28 第二天

react 组件定义

组件定义的两种常见形式

1、function,无状态组件。此种方法定义的组件没有 this 指向问题,但是在 react16.8 之后的版本中可以通过 hooks 实现组件的局部状态和生命周期,是目前官方推荐的组件写法

// 语法
// Name:组件名 props:父组件传的参数
function Name(props) {
  return jsx语法写的内容
}

// React中所有的组件都是一个function对象
function HelloWord(props) {
  return <h1>你好,世界!,count值为:{props.count}</h1>
}

2、class,可以继承自 React.Component 或者 React.PureComponent,相对来说继承自 React.PureComponent 的组件性能更快一些

// 使用了class类的继承
class HelloMessage extends React.Component {
  // render 表示渲染组件,所有的组件中都有这个方法
  render() {
    return <h5>只是一句话</h5>
  }
}
function 定义的组件案例
function Count(props) {
  console.log(props)
  const step = props.step || 1
  // useState可以在function定义的组件中设置一个局部状态
  // 此方法返回一个数组
  // 第一个值为可以使用的变量名
  // 第二个值表示改变当前数据的方法(可选)
  //  此处用到了解构赋值:
  // const arr=["小白","小红",'小绿']
  // const [a,b] = arr  // a="小白",b="小红"
  // const [count, setCount] = React.useState(0)
  // const [title, setTitle] = useState('当前的标题')
  const [count, setCount] = useState(0)
  const [list, setList] = useState([])
  const keyUpHandle = (e) => {
    if (e.keyCode === 13) {
      setList([{ id: Date.now(), content: e.target.value }, ...list])
    }
  }
  return (
    <div>
      <h5>当前的步长为:{step}</h5>
      <ul>
        {list.map((item) => (
          <li key={item.id}>{item.content}</li>
        ))}
      </ul>
      <input type="text" placeholder="请输入内容" onKeyUp={keyUpHandle} />
      <button onClick={() => setCount(count + step)}>计数值为:{count}</button>
    </div>
  )
}
ReactDOM.render(
  <div>
    <Count step={5} />
    <Count step="5" />
  </div>,
  document.getElementById('app')
)
class 定义的组件
const { Component } = React
class Counter extends Component {
  constructor(props) {
    super(props)
    // class定义的组件可以通过设置state来定义局部状态
    this.state = {
      count: 1,
      title: '',
    }
    // 第一种改变this的方法,官方推荐写法
    //   this.clickHandle = this.clickHandle.bind(this)
    this.keyUpHandle = this.keyUpHandle.bind(this)
  }
  clickHandle() {
    console.log(this)
    // 在class定义的组件中改变state时需要调用setState方法
    // setState方法是异步的
    //setState的第二个参数是数据改变成功之后的回调函数
    this.setState(
      {
        count: this.state.count + 1,
      },
      function () {
        console.group('count值已经改变成功了')
      }
    )
  }
  keyUpHandle(e) {
    this.setState({
      title: e.target.value,
    })
  }
  // 每一个class组件都有一个render函数,表示当前组件输出的内容,需要有一个返回值,返回一个jsx标签,class定义的组件方法中获取属性时使用this.props固定写法
  // 当state或者props发生改变之后都会执行render方法
  // 不能在这个方法中改变state数据(会造成死循环)
  render() {
    return (
      <div>
        <h5>当前计数值为:{this.props.step}</h5>
        <button onClick={() => this.clickHandle()}>
          计数值:{this.state.count}
        </button>
        <button onClick={this.clickHandle.bind(this)}>
          计数值2{this.state.count}
        </button>
        <h5>{this.state.title}</h5>
        <input type="text" onKeyUp={this.keyUpHandle} />
      </div>
    )
  }
}
ReactDOM.render(<Counter step={6} />, document.getElementById('app'))
const { Component } = React
class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      list: [],
      page: 1,
    }
  }
  componentDidMount() {
    // console.log("组件挂载成功之后的处理函数");
    // 此处主要用来获取数据操作
    this.loadMore()
  }
  loadMore() {
    const { page, list } = this.state // 解构赋值
    fetch('http://localhost:3009/api/v1/books?page=' + page)
      .then((res) => res.json())
      .then((res) => {
        // console.log(res);
        this.setState({
          list: [...list, ...res.books],
          page: page + 1,
        })
      })
  }
  // 当组件的state或者props改变之后render方法会触发执行
  render() {
    const { list } = this.state
    console.count('执行了render方法')
    return (
      <div className="main">
        <h1>我是一个App</h1>
        <ul>
          {list.map((book) => (
            <li key={book.id}>{book.title}</li>
          ))}
        </ul>
        <button onClick={() => this.loadMore()}>加载更多</button>
      </div>
    )
  }
}
ReactDOM.render(<App />, document.getElementById('app'))

react 组件传参

父组件向子组件传参使用 props 属性进行

子组件向父组件传参使用方法调用

父组件向子组件传参列子
.ball {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  display: block;
  margin: 1rem auto;
  /* background-color: deeppink; */
  transition: all 2s;
}
const { Component } = React
class Ball extends Component {
  constructor(props) {
    super(props)
  }
  render() {
    return (
      <div style={{ backgroundColor: this.props.color }} className="ball" />
    )
  }
}

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      color: 'yellowgreen',
    }
  }
  changeColor(color) {
    this.setState({
      color, // color:color
    })
  }
  // 当组件的state或者props改变之后会触发执行
  render() {
    return (
      <div className="app">
        <button onClick={() => this.changeColor('red')}>红色</button>
        <button onClick={() => this.changeColor('orange')}>橙色</button>
        <button onClick={() => this.changeColor('green')}>绿色</button>
        <button onClick={() => this.changeColor('blue')}>蓝色</button>
        <Ball color={this.state.color} />
      </div>
    )
  }
}
ReactDOM.render(<App />, document.getElementById('app'))

父组件掉数据传递给子组件渲染页面

const { Component } = React
class Book extends Component {
  render() {
    // 接收book属性传递的内容,此处用了解构赋值{book:book}
    const { book } = this.props

    return (
      <div className="card text-white bg-primary">
        <img className="card-img-top" src={book.coverImg} alt="" />
        <div className="card-body">
          <h4 className="card-title">{book.title}</h4>
          <p className="card-text">{book.descriptions}</p>
        </div>
      </div>
    )
  }
}

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      list: [],
    }
  }
  componentDidMount() {
    this.loadMore()
  }

  loadMore() {
    fetch('http://localhost:3009/api/v1/books')
      .then((res) => res.json())
      .then((res) => {
        console.log(res.books)
        this.setState({
          list: res.books,
        })
      })
  }
  render() {
    return (
      // 遍历list数组取得单个书籍信息book,将book信息赋值给book属性,通过book属性传给Book组件
      // 遍历list数组循环创建Book组件渲染页面
      <div className="row">
        {this.state.list.map((book) => (
          <div key={book._id} className="col-md-4">
            <Book book={book} />
          </div>
        ))}
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))
子组件向父组件传参示例
const { Component } = React
class Counter extends Component {
  constructor(props) {
    super(props)
    this.state = { count: 0 }
  }
  render() {
    return (
      <div
        onClick={() => {
          this.setState({ count: this.state.count + 1 }, function () {
            // 将count值作为changeF的参数传递给changeFromChild方法
            this.props.changeF(this.state.count)
          })
        }}
      >
        点一下:{this.state.count}
      </div>
    )
  }
}
class App extends Component {
  constructor(props) {
    super(props)
    this.state = { fromChild: 0 }
    this.changeFromChild = this.changeFromChild.bind(this)
  }
  //父组件调用changeFromChild方法获取到子组件的count值
  changeFromChild(c) {
    this.setState({
      fromChild: c,
    })
  }
  render() {
    // 子组件Counter创建changeF属性绑定changeFromChild方法
    return (
      <div>
        <h5>子组件传递的数据为:{this.state.fromChild} </h5>
        <br />
        <Counter changeF={this.changeFromChild} />
      </div>
    )
  }
}
ReactDOM.render(<App />, document.getElementById('app'))

hooks

  • useState 可以定义一个局部状态数据
  • useEffect 副作用,当一个数据或者属性发生改变之后会引起的一些变化
useEffect 和 useState 的简单使用示例
const { useState, useEffect } = React
const App = (props) => {
  // 当属性或者state改变之后function会重新执行
  console.count('组件重新渲染了')
  //   useState可以在function定义的组件中设置一个局部状态
  // 此方法返回一个数组
  // 第一个值为可以使用的变量名,第二个值表示改变当前数据的方法
  // useState会对我们定义好的数据进行缓存,当数据改变之后他们不会更新,否则会造成死循环
  const [list, setList] = useState([])
  const [count, setCount] = useState(0)
  const [page, setPage] = useState(1)

  //   useEffect()叫做副作用,它有两个参数,第一个参数是一个回调函数 ,第二个参数是依赖项
  // 当依赖项数据发生改变,会执行第一个参数中的回调函数
  // 如果依赖项是一个空数组[]表示只有初始化的时候会执行一次
  useEffect(() => {
    console.count('初始化')
  }, [])
  useEffect(() => {
    loadData()
  }, [page])
  const loadData = () => {
    fetch('http://localhost:3009/api/v1/books?page=' + page)
      .then((res) => res.json())
      .then((res) => setList([...list, ...res.books]))
  }
  // useEffect(() => {
  //   console.count('list count值变了')
  // }, [list, count])
  return (
    <div>
      <h3 onClick={() => setCount(count + 1)}>这是一个组件-{count}</h3>
      <ul>
        {list.map((item) => (
          <li key={item._id}>{item.title}</li>
        ))}
      </ul>
      <button onClick={() => setPage(page + 1)}>加载数据</button>
    </div>
  )
}
ReactDOM.render(<App />, document.getElementById('app'))

7/29 第三天

react 组件生命周期

常用生命周期钩子函数

  • componentWillMount 组件挂载完成加载数据
  • shouldComponentUpdate 主要用来对组件做性能优化的时候使用,通过 return 布尔值来判断组件是否更新
class Ball extends React.Component {
  componentWillMount() {
    console.log('组件Ball将要挂载')
  }
  componentDidMount() {
    console.log('组件Ball挂载完成')
  }
  componentWillUnmount() {
    console.log('组件Ball将要卸载')
  }
  componentWillReceiveProps(p) {
    console.log(p)
    console.log('组件将要接收新的属性')
  }
  render() {
    return <div className="ball" />
  }
}
class App extends React.Component {
  // 初始化阶段
  constructor(props) {
    super(props)
    this.state = {
      title: '标题',
      count: 0,
      list: ['小凡', '陆雪琪', '碧瑶'],
    }
  }
  // 挂载阶段
  componentWillMount() {
    console.log('组件将要挂载')
  }
  componentDidMount() {
    console.log('组件挂载完成')
  }
  // shouldComponentUpdate 主要用来对组件做性能优化的时候使用
  // 更新阶段,当状态或者属性发生改变之后会触发更新阶段的钩子函数,在更新阶段 不能修改数据
  shouldComponentUpdate(nextProps, nextState) {
    // console.log(p);
    // console.log(s);
    console.log('组件是否需要更新')
    if (nextState.count % 2 === 0) {
      return false // 返回值为false,组件不需要更新,不会执行render方法
    } else {
      return true
    }
  }
  componentWillUpdate() {
    console.log('组件将要更新')
  }
  componentDidUpdate() {
    console.log('组件更新完成')
  }
  componentWillReceiveProps() {
    console.log('组件将要接收新的属性')
  }
  // 卸载阶段
  componentWillUnmount() {
    console.log('组件将要卸载')
  }
  render() {
    console.log('render执行了')
    return (
      <div>
        <h5>{this.state.title}</h5>
        <button
          onClick={() =>
            this.setState({
              count: this.state.count + 1,
            })
          }
        >
          {this.state.count}
        </button>
        {this.state.count % 2 == 0 ? <></> : <Ball r={Math.random()} />}
      </div>
    )
  }
}
ReactDOM.render(<App />, document.getElementById('app'))

ref 操作

class 定义的组件中可以使用 this.refs

function 定义的组件中可以使用 useRef

  • 非受控组件,组件的数据不受 state 状态管理,在获取的时候直接通过 ref 属性进行获取
class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      name: '',
      skills: '',
      desc: '',
    }
  }
  render() {
    return (
      <ul>
        <li>
          <input ref="name" type="text" placeholder="请输入名字" />
        </li>
        <li>
          <input ref="desc" type="text" placeholder="请输入简介" />
        </li>
        <li>
          <input ref="skills" type="text" placeholder="请输入技能" />
        </li>
        <li>
          <button
            onClick={() => {
              // 非受控组件,组件的数据不受state状态管理,在获取的时候直接通过ref属性进行获取
              console.log(this.refs)
              console.log(this.refs.name.value)
              console.log(this.refs.skills.value)
              console.log(this.refs.desc.value)
            }}
          >
            提交
          </button>
        </li>
      </ul>
    )
  }
}
ReactDOM.render(<App />, document.getElementById('app'))

获取表单数据

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      name: '',
      skills: '',
      desc: '',
    }
    this.keyUpHandle = this.keyUpHandle.bind(this)
  }
  keyUpHandle(e) {
    console.log(e.target.dataset.id)
    const obj = {}
    // 对象动态赋值,获取input输入的内容
    obj[e.target.dataset.id] = e.target.value
    this.setState(obj)
  }
  render() {
    return (
      <ul>
        <li>
          <input
            onKeyUp={this.keyUpHandle}
            data-id="name"
            type="text"
            placeholder="请输入名字"
          />
        </li>
        <li>
          <input
            onKeyUp={this.keyUpHandle}
            data-id="desc"
            type="text"
            placeholder="请输入简介"
          />
        </li>
        <li>
          <input
            onKeyUp={this.keyUpHandle}
            data-id="skills"
            type="text"
            placeholder="请输入技能"
          />
        </li>
        <li>
          <button
            onClick={() => {
              console.log(this.state)
            }}
          >
            提交
          </button>
        </li>
      </ul>
    )
  }
}
ReactDOM.render(<App />, document.getElementById('app'))

ref-function 操作

const { useRef } = React
function App() {
  const name = useRef() // 可以为标签定义一个ref属性,在组件中直接获取他的内容
  const desc = useRef()
  const skills = useRef()
  return (
    <ul>
      <li>
        <input ref={name} type="text" placeholder="请输入名字" />
      </li>
      <li>
        <input ref={desc} type="text" placeholder="请输入简介" />
      </li>
      <li>
        <input ref={skills} type="text" placeholder="请输入技能" />
      </li>
      <li>
        <button
          onClick={() => {
            console.log(name.current.value)
            console.log(desc.current.value)
            console.log(skills.current.value)
          }}
        >
          提交
        </button>
      </li>
    </ul>
  )
}
ReactDOM.render(<App />, document.getElementById('app'))

context

Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props。

Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差。

如果你只是想避免层层传递一些属性,组件组合(component composition)有时候是一个比 context 更好的解决方案。

// 创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。
const mainContext = React.createContext()
const { Provider } = mainContext
class B extends React.Component {
  constructor(props) {
    super(props)
    this.state = {}
  }
  render() {
    console.log(this.context)
    return (
      <>
        <h1>我是B组件</h1>
      </>
    )
  }
}
B.contextType = mainContext //第一种调用Context内参数的方法

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {}
  }
  // static 这个类属性来初始化你的 contextType。
  static contextType = mainContext //第二种调用Context内参数的方法
  render() {
    return (
      <>
        <B />
      </>
    )
  }
}
//每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。

// Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。

// 当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件退出更新的情况下也能更新。
ReactDOM.render(
  <Provider value={{ title: '我是一个标题', color: 'orange' }}>
    <App />
  </Provider>,
  document.getElementById('app')
)

useContext

useContext 可以获取当前组件的上下文内容

const mainContext = React.createContext()
const { Provider } = mainContext
function B() {
  // useContext可以获取当前组件的上下文内容
  const c = React.useContext(mainContext)
  console.log(c)
  return (
    <>
      <h1>这是一个组件B</h1>
    </>
  )
}
function App() {
  return (
    <>
      <B />
    </>
  )
}

ReactDOM.render(
  <Provider value={{ title: '标题', color: 'orange' }}>
    <App />
  </Provider>,
  document.getElementById('app')
)

使用 context 上下文进行跨组件传参

const mainContext = React.createContext()
const { Provider } = mainContext
function B() {
  // 跨组件传参,使用context上下文
  // useContext可以获取当前组件的上下文内容
  const { counter } = React.useContext(mainContext)
  // console.log(c)
  return (
    <>
      <h1 onClick={() => counter.setCount(counter.count + 1)}>这是一个组件B</h1>
    </>
  )
}
function App(props) {
  const { counter } = React.useContext(mainContext)
  // App组件里面的所有子标签,可以通过{props.children}展示,类似于vue组件里面的插槽
  return (
    <>
      <h1>当前的count值为:{counter.count}</h1>
      <B />
      {props.children}
    </>
  )
}

function AppProvider(props) {
  const [count, setCount] = React.useState(0)
  // 创建的局部状态
  return (
    <Provider value={{ counter: { count, setCount } }}>
      {props.children}
    </Provider>
  )
}

ReactDOM.render(
  <AppProvider>
    <App />
  </AppProvider>,
  document.getElementById('app')
)

7/30 第四天

全选/反选

const { useState, useEffect } = React
function CheckAll() {
  const [checkAll, setCheckAll] = useState(false)
  const [isCheckAllClicked, setCheckAllClick] = useState(false)
  const [list, setList] = useState([
    {
      id: 1,
      name: '从你的全世界路过',
      checked: true,
    },
    {
      id: 2,
      name: '沙丘',
      checked: false,
    },
    {
      id: 3,
      name: '三体',
      checked: false,
    },
    {
      id: 4,
      name: '球状闪电',
      checked: false,
    },
  ])
  useEffect(() => {
    // 设置全选
    setCheckAll(list.filter((item) => item.checked).length == list.length)
  }, [list])
  // 全选按钮改变之后
  useEffect(() => {
    if (isCheckAllClicked) {
      setList(
        list.map((item) => {
          item.checked = checkAll
          return item
        })
      )
      setCheckAllClick(false)
    }
  }, [checkAll])
  return (
    <div>
      <p>
        <label
          onClick={() => {
            setCheckAllClick(true)
            setCheckAll(!checkAll)
          }}
        >
          <input type="checkbox" onChange={() => {}} checked={checkAll} />
          全选
        </label>
      </p>
      <ul>
        {list.map((item) => (
          <li key={item.id}>
            <label
              onClick={() => {
                list.find((i) => i.id === item.id).checked = !list.find(
                  (i) => i.id === item.id
                ).checked
                setList([...list])
              }}
            >
              <input
                onChange={() => {}}
                type="checkbox"
                checked={item.checked}
              />
              {item.name}
            </label>
          </li>
        ))}
      </ul>
    </div>
  )
}

function App() {
  return <CheckAll />
}
ReactDOM.render(<App />, document.getElementById('app'))

使用 react 脚手架搭建项目

npx create-react-app XXXX

cd XXXX   #进入文件夹

npm start #启动项目

创建.jsx文件后在文件内输入rfce按Tap键快速生成function组件(rcc快速生成class组件,但是function组件用起来更为方便)

Ant Design - 一套企业级 UI 设计语言和 React 组件库:https://ant-design.gitee.io/index-cn

8/3 第五天

react路由

npm i react-router-dom #安装路由插件
Router 表示所有需要使用路由的部分都必须包含在此节点内部,一个项目只需要有一个此节点就好
此Router有两种常见的形式hash browser
Route 表示一个路由对象,需要属性path component
	render方法,可以使用一个组件渲染路由内容,注意:此种方式渲染的组件是没有路由相关的属性信息传递的,需要使用withRouter方法把路由属性带到组件内部
Link 生成一个a标签

withRouter是一个函数,接收一个组件作为参数,返回一个新的组件,为组件添加一些路由属性信息

const About = (props)=>{
    console.log(props);
    return <h1>About us</h1>
}
// 此处为高阶组件
const AboutPage = withRouter(About)

*** 高阶组件 ***:把一个组件当作参数传递到一个方法里面为它进行封装,添加一些新的属性,返回一个新的组件 ,相当于js中的高阶函数(回调函数)

function App() {
  return (
    <Router>
      <div className="App">
        <ul>
          <li>
            <Link exact to="/">首页</Link>
          </li>
          <li>
            <Link to="/list?t=cart">列表</Link>
          </li>
          <li>
            <Link to="/p">People</Link>
          </li>
        </ul>
        <hr />
        {/* Route是一个组件 */}
        <div className="container">
          {/* exact 表示完全匹配 */}
          <Route path="/" exact component={Home} />
          <Route path="/list" component={List} />
          <Route path="/p" component={People} />
          {/* render方式渲染组件,没有直接使用component指定组件
              这时候在路由对应的组件中没有history和location等路由的属性信息
          */}
          <Route path="/about" render={() => <About />} />
        </div>
      </div>
    </Router>
  );
}
// hsitory.push('/list')	编程跳转
const Home = (props) => {
  const { history } = props;
  return (
    <div>
      <h1>首页</h1>
      <Button
        onClick={() => {
          // 使用编程式跳转
          history.push("/list");
        }}
      >
        列表页
      </Button>
      <Button
        onClick={() => {
          // 使用编程式跳转
          history.push("/about");
        }}
      >
        关于我们
      </Button>
    </div>
  );
};
URLSearchParams

路由组件中会包含history\location\match可以打印props查看

使用new URLSearchParams 获取当前查询条件

使用模块qs也能获取查询条件

function List(props){
    console.log(props);
    const sq = new URLSearchParams(props.location.search);
    // get方法通过url中?后面的键名
    console.log(sq.get('t'))
    return ()
}

路由嵌套

所谓路由嵌套就是在路由跳转的组件内部编写Route组件

私有路由
import React from "react";
import { Route, Redirect } from "react-router-dom";

// 此处定义一个私有路由 需要登录之后才能访问
// PrivateRoute(props)也可以,该方法在对应的私有路由博客那篇文章里有展示
function PrivateRoute({ children, ...rest }) {
  const isLogined = localStorage.getItem("token") ? true : false;
  // console.group("私有路由判断");
  // console.log(isLogined);
 // console.groupEnd();
  return (
    <Route
      {...rest}
      render={() => (isLogined ? children : <Redirect to="/login" />)}
    />
  );
}

export default PrivateRoute;
私有路由的使用

通过封装好的权限验证组件将需要进行路由验证的的组件包裹

import React from "react";
import {
  HashRouter as Router,
  Route,
  Link,
  NavLink,
  Switch,
} from "react-router-dom";
import List from "./components/List";
import People from "./components/People";
import PrivateRoute from "./components/PrivateRoute";
import Login from "./pages/Login";

function App() {
  return (
    <Router>
      <div className="App">
        {/* Route是一个组件 */}
        <div className="container">
          {/* Switch 只会匹配一个路由内容 */}
          <Switch>
            <Route path="/login" render={() => <Login />} />
            {/* exact 表示完全匹配 */}
            <Route path="/" exact component={Home} />
                // 此处使用了路由权限验证
            <PrivateRoute path="/list">
              <List />
            </PrivateRoute>
			// params传参需要使用/:占位符
            <PrivateRoute path="/p/:o">
              <People />
            </PrivateRoute>
            {/* render方式渲染组件,没有直接使用component指定组件
              这时候在路由对应的组件中没有history和location等路由的属性信息
          */}
          </Switch>
        </div>
      </div>
    </Router>
  );
}

NavLink生成的a标签多一个active属性,可以利用此特性给选中的a标签添加样式

<NavLink>是<Link>的一个特定版本,会在匹配上当前的url的时候给已经渲染的元素添加参数,组件的属性有

activeClassName(string):设置选中样式,默认值为active
activeStyle(object):当元素被选中时,为此元素添加样式
exact(bool):为true时,只有当导致和完全匹配class和style才会应用
strict(bool):为true时,在确定为位置是否与当前URL匹配时,将考虑位置pathname后的斜线
isActive(func)判断链接是否激活的额外逻辑的功能

8/4 第四天

redux

状态管理工具,遵循的单项数据流。所谓单项数据流就是数据单向流动

reducer是用来改变数据的

action是用来组织数据,每一个action都需要包含一个type属性,type的类型不能重复是唯一的

state是用来存储数据的

如果要改变数据是通过dispatch派发一个action在reducer中改变数据

redux和vuex的区别:

vuex只能在vue中使用

redux可以和任何一个前端框架进行结合

redux使用

npm i redux	#安装依赖项
import { createStore, combineReducers } from 'redux'
// 定义reducer的时候它是一个function接收两个参数
// 参数一 初始状态
// 参数二 action 表示以什么方式改变数据
function counter(state = { count: 1 }, action) {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        count: state.count + action.payload.step,
      }
    default:
      return state
  }
}

const store = createStore(rootReducer) // 初始化创建一个store

console.log(store.getState())

combineReducers 方法

Redux 提供了一个combineReducers方法,用于 Reducer 的拆分。你只要定义各个子 Reducer 函数,然后用这个方法,将它们合成一个大的 Reducer。

import { combineReducers } from 'redux';
// 还要引入其中reducer各个分组件,此处没写,懒得:import...
const chatReducer = combineReducers({
  chatLog,
  statusMessage,
  userName
})
export default todoApp;

关联redux和react

需要安装插件:

  • 注意:引入第三方模块要放在自己创建的模块前面
npm i react-redux
Provider 提供者

使用Provider 提供者 方法 通过store属性将redux内容提供给组件

import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import App from './App'
import store from './store'

ReactDOM.render(
    // 此处第一个store是Provider的属性,第二个store是变量名
  <Provider store={store}>
    <App />,
  </Provider>,
  document.getElementById('root')
)

connect 映射

connect 连接 react-redux模块中的方法

import { connect } from 'react-redux'

function App(props) {
  console.log(props)
  return (
    <div className="App">
      <People />
    </div>
  )
}
// 1️⃣connect方法完整版
// state表示所有数据
function mapStateToProps(state) {
  return state
}
// 通过connect可以把redux中的state数据和dispatch方法映射到组件的属性中
export default connect(mapStateToProps)(App)

// 2️⃣connect方法简写
export default connect((state)=>state)(App)
dispatch 派发
function App(props) {
  console.log(props)
  const { count, dispatch } = props //将count内容从props中解构出来
  return (
    <div className="App">
      <h1> {count}</h1>
      <button
		// 通过事件回调dispatch方法派发一个action在reducer中改变数据
        onClick={() =>
          dispatch({
            type: 'ADD',
            payload: {
              step: 2,
            },
          })
        }
      ></button>
      <Counter />
    </div>
  )
}

redux-thunk 处理异步

第三方插件

作用:解决redux里面处理异步操作的事情

npm i redux-thunk
import { createStore, compose, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducers from './reducers'
// combineReducers 合并多个reducer为一个

//使用了redux-thunk插件之后可以返回一个function作为dispatch的参数
// 判断当前的action是什么
//如果是一个function那么会自动的把dispatch当作参数传递到function内部,否则直接dispatch

//初始化创建store时

第一步我们要在index.js中让middleware可用。

我们将使用到compose和applyMiddleware
compose 其作用是把一系列的函数,组装生成一个新的函数,并且从后到前,后面参数的执行结果作为其前一个的参数。compose(f, g, h) is identical to doing
(...args) => f(g(h(...args))).

applyMiddleware 最常见的使用场景是无需引用大量代码或依赖类似 Rx 的第三方库实现异步 actions。这种方式可以让你像 dispatch 一般的 actions 那样 dispatch 异步 actions。


const store = createStore(
  rootReducers,
  compose(
    applyMiddleware(...[thunk]),
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
  )
) // 初始化创建一个store


8/5 react后台管理项目搭建

需要使用的技术

antd :4.x版本 UI框架
react-router-dom:5.x版本 路由
redux:全局状态管理
axios:封装

项目创建

npx create-react-app XXXX #项目名称

安装插件

npm i antd axios redux react-redux react-router-dom redux-thunk

文件夹封装

src

  • assets

    • images
  • utils 封装网络请求和常用的类

    • request.js 发网络请求
    • config.js 配置信息
  • pages 所有的页面

  • components 组件

  • services 封装的网络请求

  • store

    • index.js 入口文件
    • actions
    • reducers
  • routes/index.js 路由

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值