容器组件(Container)
容器组件是你的数据或逻辑层并利用 stateful API,使用生命周期事件,你可以连接 state 到 redux 或者 Flux 的 storage 中,并将数据和回调作为 props 传递给子组件。
负责与Store交互
容器组件自身不会触发action(他只是披在傻瓜组件上的一层壳)
内:向傻瓜组件传递由Store获得的props
外:向Store派发用户操作傻瓜组件引起的action
父组件
import React, {PureComponent} from "react"
import PropTypes from 'prop-types';
import axios from "axios"
import ProductList from "views/product-list"
class NwdContainer extends React.Component {
constructor(props){
super(props)
}
state = {
names: ""
}
componentDidMount() {
var _this = this;
axios.get('https://api.github.com/search/users?q=tom+repos:%3E42+followers:%3E1000')
.then(function (res) {
_this.setState({
names: res.data.total_count
})
})
}
render() {
return (
<div>
<ProductList names={this.state.names}></ProductList>
</div>
)
}
}
export default NwdContainer复制代码
子组件(展示组件)
import React, {PureComponent} from "react"
import PropTypes from 'prop-types';
const ProductList = (props) => {
return (
<div>
{props.names}
</div>
)
}
export default ProductLis复制代码
如上 容器组件,就是负责获取用户数据,然后以props的形式传递给展示组件ProductList来渲染。容器组件也不会在页面中渲染出具体的DOM节点,因此,它通常就充当数据源的角色。目前很多常用的框架,也都采用这种组件形式。如:React Redux的connect(), Relay的createContainer(), Flux Utils的Container.create()等。
展示组件
展示组件 使用 props、render 和 context (无状态API),并且由于不需要使用生命周期相关 Api,可以使用纯函数来简化编写 即 函数式组件
import React, {PureComponent} from "react"
import {PropTypes} from 'prop-types';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
const NwdCard = (props) =>{
console.log(props)
return (
<div>{props.name}</div>
)
}
export default NwdCard复制代码
展示组件 仅从 props 接收数据和回调,这些数据和回调可以由其容器组件(父组件)提供
父组件
import React, {PureComponent} from "react"
import {PropTypes} from 'prop-types';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
import NwdCard from "views/nwd-card";
export default class Form extends React.Component {
constructor(props) {
super(props)
}
state = {
name: "你我贷1"
}
componentDidMount() {
this.setState(() =>{
return {
name:"你我贷2"
}
})
}
render() {
return (
<div>
<NwdCard name={this.state.name}></NwdCard>
</div>
)
}
}复制代码
子组件
import React, {PureComponent} from "react"
import {PropTypes} from 'prop-types';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
const NwdCard = (props) =>{
console.log(props)
return (
<div>{props.name}</div>
)
}
export default NwdCard复制代码
输出:
高阶组件
高阶组件是一种函数,它接受一个组件作为参数,然后返回一个新的组件
比如说 react-router-dom提供的withRouter就是典型的高阶组件,可以先说说withRouter的作用
一般路由组件可以直接访问当前路由的match,location,history,当一个非路由组件也想访问到当前路由的match,location,history对象,那么withRouter将是一个非常好的选择,可以理解为将一个组件包裹成路由组件。
路由组件:
import React, {PureComponent} from "react"
import PropTypes from 'prop-types';
import TestRouterChild from "views/test-routerchild"
class TestWithRouter extends React.Component {
constructor(props){
super(props)
}
componentDidMount() {
console.log("路由组件输出--------------")
console.log(this.props)
console.log(this.props.location.pathname)
}
render() {
return (
<div>
你我贷
<TestRouterChild></TestRouterChild>
</div>
)
}
}
export default TestWithRouter复制代码
非路由组件 (子组件):
import React, {PureComponent} from "react"
import PropTypes from 'prop-types';
class TestRouterChild extends React.Component {
constructor(props){
super(props)
}
handle = () => {
this.props.history.push("life")
}
render() {
console.log("子路由输出---------------------")
console.log(this.props)
console.log(this.props.location)
return (
<div>
<div>子组件</div>
<button onClick={this.handle}>click</button>
</div>
)
}
}
export default TestRouterChild复制代码
输出如下
通过上图看出:绿色的是非路由组件中的输出,红色的是路由组件的输出,因此子路由即非路由组件是无法获取当前路由的参数,点击跳转也无法跳转到对应的页面
引入withRouter
非路由组件(子组件)
import React, {PureComponent} from "react"
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom'
@withRouter
class TestRouterChild extends React.Component {
constructor(props){
super(props)
}
handle = () => {
this.props.history.push("life")
}
render() {
console.log("子路由输出---------------------")
console.log(this.props)
console.log(this.props.location)
return (
<div>
<div>子组件</div>
<button onClick={this.handle}>click</button>
</div>
)
}
}
export default TestRouterChild复制代码
输出如下:
通过上图可以观察到 引入withRouter后 非路由组件(子路由)可以获取当前的location history
如果不用@withRouter 可以使用 export default withRouter(TestRouterChild)
渲染回调组件(Render Callback)
渲染回调或渲染属性(props) 被用于共享或重用组件逻辑,将组件中的渲染逻辑委托给其子组件
父组件
import React, {PureComponent} from "react"
import PropTypes from 'prop-types';
import CallbackChild from "views/callback-child"
class NwdCallback extends React.Component {
constructor(props){
super(props)
}
render() {
return (
<div>
<CallbackChild>
{
(msg) => (
<div>
我的名字叫: {msg}
</div>
)
}
</CallbackChild>
</div>
)
}
}
export default NwdCallback复制代码
子组件
import React, {PureComponent} from "react"
import PropTypes from 'prop-types';
class CallBackChild extends React.Component {
constructor(props){
super(props)
}
state = {
name: "飞旋的留恋"
}
componentDidMount() {
}
render() {
console.log(this.props)
console.log(this.props.children)
return (
<div>
{this.props.children(this.state.name)}
</div>
)
}
}
export default CallBackChild复制代码
如下
注释:虽然前端开发更喜欢使用 高阶组件的可重用逻辑,但是使用 渲染回调 仍然有一些非常好的理由和优势:渲染回调减少了命名空间冲突,并更好的说明了逻辑来源。