2018-08-23 15:02:22 taoerchun 阅读数 207
  • react hooks全套教程

    这个课程主要教大家掌握react hooks的知识点以及它的基本用法,相信听说过react hooks的同学应该都知道它的意义是非常大的。 react hooks可以让我们在函数组件中使用state和生命周期,意味着我们可以不再需要臃肿的class组件了,react hooks的开发体验非常高,效率也非常高,性能也比class组件出色。 还有一点就是你可以基于react hooks封装自己的状态管理器,而不再需要redux、dva、mobx这些第三方状态管理器了。 总的来说,react hooks是非常值得学习,它能让你在开发时事半功倍。

    351 人正在学习 去看看 梁富城

React JS 组件间沟通的一些方法

 

刚入门React可能会因为React的单向数据流的特性而遇到组件间沟通的麻烦,这篇文章主要就说一说如何解决组件间沟通的问题。


 

1.组件间的关系

1.1 父子组件

ReactJS中数据的流动是单向的,父组件的数据可以通过设置子组件的props传递数据给子组件。如果想让子组件改变父组件的数据,可以在父组件中传一个callback(回调函数)给子组件,子组件内调用这个callback即可改变父组件的数据。

 

var MyContainer = React.createClass({
	getInitialState: function(){
		return {
			list: ['item1', 'item2'],
			curItem: 'item1'
		}
	},
	// 改变curItem的回调函数
	changeItem: function(item){
		this.setState({
			curItem: item
		});
	},
	render: function(){
		return (
			<div>
				The curItem is: {this.state.curItem}
				<List list={this.state.list} changeItem={this.changeItem}/>
			</div>
		)
	}
});
 
var List = React.createClass({
	onClickItem: function(item){
		this.props.changeItem(item);
	},
	render: function(){
		return (
			<ul>
				{
					(function(){
						var self = this;
						return this.props.list.map(function(item){
							return (
								<li onClick={self.onClickItem.bind(self, item)}>I am {item}, click me!</li>		
							)
						});
					}.bind(this))()
		
				}
 
			</ul>
		)
	}
})
 
 
ReactDOM.render(
  <MyContainer />,
  document.getElementById('example')
);

<MyContainer />是<List />的父组件,<MyContainer />通过props传递list数据给<List />组件,如果<MyContainer />中的list改变,<List />会重新渲染列表数据。而<List />可以通过<MyContainer />传来的changeItem函数,改变<MyContainer />的curItem数据。

 

1.2 兄弟组件

当两个组件不是父子关系,但有相同的父组件时,将这两个组件称为兄弟组件。兄弟组件不能直接相互传送数据,此时可以将数据挂载在父组件中,由两个组件共享:如果组件需要数据渲染,则由父组件通过props传递给该组件;如果组件需要改变数据,则父组件传递一个改变数据的回调函数给该组件,并在对应事件中调用。

var MyContainer = React.createClass({
	getInitialState: function(){
		return {
			list: ['item1', 'item2'],
			curItem: 'item1'
		}
	},
	// 改变curItem的回调函数
	changeItem: function(item){
		this.setState({
			curItem: item
		});
	},
	render: function(){
		return (
			<div>
				The curItem is: {this.state.curItem}
				<List list={this.state.list} curItem={this.state.curItem} />
				<SelectionButtons changeItem={this.changeItem}/>
			</div>
		)
	}
});
 
var List = React.createClass({
		
	render: function(){
		var selectedStyle = {
			color: 'white',
			background: 'red'
		};
 
		return (
			<ul>
 
				{
					(function(){
						var self = this;
						return this.props.list.map(function(item){
							var itemStyle = (item == self.props.curItem) ? selectedStyle : {};
							return (
								<li style={itemStyle}>I am {item}!</li>		
							)
						});
					}.bind(this))()
		
				}
 
			</ul>
		)
	}
});
 
var SelectionButtons = React.createClass({
	onClickItem: function(item){
		this.props.changeItem(item);
	},
	render: function(){
		return (
			<div>
				<button onClick={this.onClickItem.bind(this, 'item1')}>item1</button>
				<button onClick={this.onClickItem.bind(this, 'item2')}>item2</button>
			</div>
		)
	}
});
 
 
ReactDOM.render(
  <MyContainer />,
  document.getElementById('example')
);

如上述代码所示,共享数据curItem作为state放在父组件<MyContainer />中,将回调函数changeItem传给<SelectionButtons />用于改变curItem,将curItem传给<List />用于高亮当前被选择的item。

 

2. 组件层次太深的噩梦

兄弟组件的沟通的解决方案就是找到两个组件共同的父组件,一层一层的调用上一层的回调,再一层一层地传递props。如果组件树嵌套太深,就会出现如下惨不忍睹的组件亲戚调用图。

share-parent-components

 

下面就来说说如何避免这个组件亲戚图的两个方法:全局事件和Context。

 

3. 全局事件

可以使用事件来实现组件间的沟通:改变数据的组件发起一个事件,使用数据的组件监听这个事件,在事件处理函数中触发setState来改变视图或者做其他的操作。使用事件实现组件间沟通脱离了单向数据流机制,不用将数据或者回调函数一层一层地传给子组件,可以避免出现上述的亲戚图。

事件模块可以使用如EventEmitter或PostalJS这些第三方库,也可以自己简单实现一个:

 

var EventEmitter = {
    _events: {},
    dispatch: function (event, data) {
        if (!this._events[event]) return; // no one is listening to this event
        for (var i = 0; i < this._events[event].length; i++)
            this._events[event][i](data);
    },
    subscribe: function (event, callback) {
      if (!this._events[event]) this._events[event] = []; // new event
      this._events[event].push(callback);
    },
    unSubscribe: function(event){
    	if(this._events && this._events[event]) {
    		delete this._events[event];
    	}
    }
}

 

组件代码如下:

 

var MyContainer = React.createClass({
 
	render: function(){
		return (
			<div>
				<CurItemPanel />
				<SelectionButtons/>
			</div>
		)
	}
});
 
var CurItemPanel = React.createClass({
	getInitialState: function(){
		return {
			curItem: 'item1'
		}
	},
	componentDidMount: function(){
		var self = this;
		EventEmitter.subscribe('changeItem', function(newItem){
			self.setState({
				curItem: newItem
			});
		})
	},
	componentWillUnmount: function(){
		EventEmitter.unSubscribe('changeItem');
	},
	render: function(){
		return (
			<p>
				The curItem is:  {this.state.curItem}
			</p>
		)
	}
 
});
 
var SelectionButtons = React.createClass({
	onClickItem: function(item){
		EventEmitter.dispatch('changeItem', item);
	},
	render: function(){
		return (
			<div>
				<button onClick={this.onClickItem.bind(this, 'item1')}>item1</button>
				<button onClick={this.onClickItem.bind(this, 'item2')}>item2</button>
			</div>
		)
	}
});
 
 
ReactDOM.render(
  <MyContainer />,
  document.getElementById('example')
);

 

事件绑定和解绑可以分别放在componentDidMount和componentWillUnMount中。由于事件是全局的,最好保证在componentWillUnMount中解绑事件,否则,下一次初始化组件时事件可能会绑定多次。 使用事件模型,组件之间无论是父子关系还是非父子关系都可以直接沟通,从而解决了组件间层层回调传递的问题,但是频繁地使用事件实现组件间沟通会使整个程序的数据流向越来越乱,因此,组件间的沟通还是要尽量遵循单向数据流机制。

 

4. context(上下文)

使用上下文可以让子组件直接访问祖先的数据或函数,无需从祖先组件一层层地传递数据到子组件中。

MyContainer组件:

 

var MyContainer = React.createClass({
	getInitialState: function(){
		return {
			curItem: 'item1'
		}
	},
	childContextTypes: {
		curItem: React.PropTypes.any,
		changeItem: React.PropTypes.any
	},
	getChildContext: function(){
		return {
			curItem: this.state.curItem,
			changeItem: this.changeItem
		}
	},
	changeItem: function(item){
		this.setState({
			curItem: item
		});
	},
	render: function(){
		return (
			<div>
				<CurItemWrapper />
				<ListWrapper changeItem={this.changeItem}/>
			</div>
		)
	}
});

childContextTypes用于验证上下文的数据类型,这个属性是必须要有的,否则会报错。getChildContext用于指定子组件可直接访问的上下文数据。

CurItemWrapper组件和CurItemPanel组件:

var CurItemWrapper = React.createClass({
	render: function(){
		return (
			<div>
				<CurItemPanel />
			</div>
		)
	}
});
 
var CurItemPanel = React.createClass({
	contextTypes: {
		curItem: React.PropTypes.any
	},
	render: function(){
		return (
			<p>
				The curItem is: {this.context.curItem}
			</p>
		)
	}
 
});

 

在<CurItemPanel />通过this.context.curItem属性访问curItem,无需让<CurItemWrapper />将curItem传递过来。必须在contextTypes中设置curItem的验证类型,否则this.context是访问不了curItem的。

ListWrapper组件和List组件:

 

var ListWrapper = React.createClass({
	render: function(){
		return (
			<div>
				<List />
			</div>
		)
	}
});
 
var List = React.createClass({
	contextTypes: {
		changeItem: React.PropTypes.any
	},
	onClickItem: function(item){
		this.context.changeItem(item);
	},
	render: function(){
		return (
			<ul>
				<li onClick={this.onClickItem.bind(this, 'item1')}>I am item1, click me!</li>
				<li onClick={this.onClickItem.bind(this, 'item2')}>I am item2, click me!</li>
			</ul>
		)
	}
});

同上,<List />可以通过this.context.changeItem获取<MyContainer />的改变curItem的changeItem函数。

 

5. Redux

为了在React中更加清晰地管理数据,Facebook提出了Flux架构,而redux则是Flux的一种优化实现。

关于redux,另外一个比我帅气的同事已经写了一篇详细的redux介绍博文,传送门在下面,有兴趣的可以去看看。

http://www.alloyteam.com/2015/09/react-redux/

 

当Redux与React搭配使用时,一般都是在最顶层组件中使用Redux。其余内部组件仅仅是展示性的,发起dispatch的函数和其他数据都通过props传入。然后,我们又会看到那熟悉的组件亲戚调用图:

share-parent-components

 

如果使用全局事件解决方案,那么redux中漂亮的,优雅的单向数据管理方式就会遭到破坏。于是,使用context就成了解决这种层层回调传递问题的首选方案,下面给出一个简单例子:

index.js:

import { createStore, applyMiddleware } from 'redux';
import reducers from "./reducers"
import { Provider } from 'react-redux'
 
import React, {Component} from 'react';
import { render } from 'react-dom';
import App from './App';
 
let store = createStore(reducers);
 
render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

 

reducers.js:

export default function changeItem(state = {'curItem': 'item1'}, action){
  switch(action.type) {
    case 'CHANGE_ITEM':
      return Object.assign({}, {
        curItem: action.curItem
      });
    default:
      return state;
  }
}

actions.js:

 

export function changeItem(item) {
  return {
    type: 'CHANGE_ITEM',
    curItem: item
  }
}

App.js(组件代码):

import React, {Component} from 'react';
import { connect, Provider } from 'react-redux';
import { changeItem } from './actions';
 
class App extends Component{
  constructor(props, context) {
    super(props, context);
  }
  getChildContext() {
    return {
      curItem: this.props.curItem,
      changeItem: this.props.changeItem
    }
  }
  render() {
    return (
      <div>
        <CurItemPanel />
        <List />
      </div>
 
    )
  }
}
 
App.childContextTypes = {
  curItem: React.PropTypes.any,
  changeItem: React.PropTypes.any
};
 
class CurItemPanel extends Component {
  constructor(props, context) {
    super(props, context);
  }
  render() {
    return (
      <div>The curItem is: {this.context.curItem}</div>
    )
  }
}
CurItemPanel.contextTypes = {
  curItem: React.PropTypes.any
};
 
class List extends Component {
  constructor(props, context) {
    super(props, context);
  }
  onClickItem (item){
    this.context.changeItem(item);
  }
  render() {
    return (
      <ul>
        <li onClick={this.onClickItem.bind(this, 'item1')}>I am item1, click me!</li>
        <li onClick={this.onClickItem.bind(this, 'item2')}>I am item2, click me!</li>
      </ul>
    )
  }
}
 
List.contextTypes = {
  changeItem: React.PropTypes.any
};
 
let select = state => { return state};
 
function mapDispatchToProps(dispatch) {
  return {
    changeItem: function(item) {
      dispatch(changeItem(item));
    }
  };
}
 
export default(connect(select, mapDispatchToProps))(App);

 

上述代码中,Store是直接与智能组件<App />交互的,所以Store将state数据curItem和dispatch函数changeItem作为props传给了<App />。在<App />中将curItem数据和changeItem函数作为上下文,作为子组件的笨拙组件就可以之间通过上下文访问这些数据,无需通过props获取。

注:

1.redux的官方文档中是使用ES6语法的,所以这里的React代码也使用ES6做例子

2.运行上述代码需要构建代码,大家可以在redux的github中下载redux带构建代码的examples,然后将代码替换了再构建运行。

 

 

6. transdux

偶尔之间发现一个叫transdux的东西。这是一个类redux的数据沟通框架,作者的初衷是为了让用户写出比redux更简洁的代码,同时还能获得[fl|re]dux的好处。用户端使用该框架的话,可以解决下面一些redux中不好看的代码写法:

1)redux中需要创一个全局的store给Provider。Transdux中省略这个store。

2)redux与react搭配使用时,redux需要通过connect方法将数据和dispatch方法传给redux。Transdux没有connect。

3)redux需要把action当props传下去,跟传callback一样。Trandux不会出现这种传递。

 

使用transdux需要以下步骤

(1)安装trandux

npm install transdux –save

 

(2)把component包到Transdux里

import React, {Component} from 'react';
import Transdux from 'transdux';
import App from './TransduxApp.js';
import { render } from 'react-dom';
 
render(
  <Transdux>
    <App />
  </Transdux>,
  document.getElementById('root')
);

 

(3)定义component能干什么,component的状态如何改变

 

import React, {Component} from 'react';
import {mixin} from 'transdux'
import ChangeButton from './ChangeButton';
 
// 定义action是怎么变的
let actions = {
  addHello(obj, state, props) {
    // 返回state
    return {
      msg: obj.msg
    }
  }
};
 
 
class App extends Component{
  constructor(props){
    super(props);
    this.state = {msg: 'init'};
  }
  render() {
    // 应该传入调用了store.dispatch回调函数给笨拙组件
    return (
      <div>
        {this.state.msg}
        <ChangeButton />
      </div>
 
    )
  }
}
 
export default mixin(App, actions);

 

(4)使用dispatch

import React, {Component} from 'react';
import {mixin} from 'transdux'
import minApp from './TransduxApp';
class ChangeButton extends Component{
  click() {
    this.dispatch(minApp, 'addHello', {'msg': 'hello world'});
  }
  render() {
    return (
      <div>
        <button onClick={this.click.bind(this)}>change content</button>
      </div>
 
    )
  }
}
export default mixin(ChangeButton, {});

mixin方法扩为<ChangeButton />扩展了一个dispatch方法。dispatch方法需要三个参数:接手消息的组件、改变组件的actions、传递的对象。<ChangeButton />的按钮事件处理函数调用了该dispatch后,会改变<App />中的状态。

 

使用了Clojure的Channel通信机制,实现了组件与组件之间的直接通信。这种通信的效果类似与events,每个组件可以维护着自己的state,然后用mixin包装自己传给其他组件改变状态。

 

Transdux的传送门在下面,有兴趣的同学可以去看看:

https://blog.oyanglul.us/javascript/react-transdux-the-clojure-approach-of-flux.html

 

小结

简单的的组件沟通可以用传props和callback的方法实现,然而,随着项目规模的扩大,组件就会嵌套得越来越深,这时候使用这个方法就有点不太适合。全局事件可以让组件直接沟通,但频繁使用事件会让数据流动变得很乱。如果兄弟组件共同的父组件嵌套得太深,在这个父组件设置context从而直接传递数据和callback到这两个兄弟组件中。使用redux可以让你整个项目的数据流向十分清晰,但是很容易会出现组件嵌套太深的情况,events和context都可以解决这个问题。Transdux是一个类redux框架,使用这个框架可以写出比redux简洁的代码,又可以得到redux的好处。

原博客地址:http://www.alloyteam.com/2016/01/some-methods-of-reactjs-communication-between-components/ 

2018-09-14 13:30:13 qq_35713752 阅读数 435
  • react hooks全套教程

    这个课程主要教大家掌握react hooks的知识点以及它的基本用法,相信听说过react hooks的同学应该都知道它的意义是非常大的。 react hooks可以让我们在函数组件中使用state和生命周期,意味着我们可以不再需要臃肿的class组件了,react hooks的开发体验非常高,效率也非常高,性能也比class组件出色。 还有一点就是你可以基于react hooks封装自己的状态管理器,而不再需要redux、dva、mobx这些第三方状态管理器了。 总的来说,react hooks是非常值得学习,它能让你在开发时事半功倍。

    351 人正在学习 去看看 梁富城

微信小程序开发交流qq群   173683895

   承接微信小程序开发。扫码加微信。

 

组件:

通过组件,可以将UI拆分成独立的,可重复使用的部分,从概念上讲,组件就像javaScript函数,它们接受任意输入(称之为道具),并返回描述屏幕上应显示内容的Recat元素。

1.定义一个简单的组件并且使用组件(注意:组件名称第一个字母必须大写)

function Demo(user){
    return <div>
               <h1>hello,{user.name};</h1>
               <h2>请问你是{user.age}岁吗?</h2>
           </div>;
}
const _demo =<Demo name='Jay' age='16' />;
ReactDOM.render(
    _demo,
    document.getElementById('root')
)

代码运行效果图:

 

 

2.组件内镶入组件

function Detail(article){
    return <h3>文章详情:{article.name}, {article.detail}</h3>;
}
function Title(article){
    return <h1>文章标题:{article.title}</h1>;
}
function Block(){
    return (
      <div>
        <Title title='今天早上你吃了什么?'/>
        <Detail name='张三' detail='我吃了一个苹果。'/>
        <Detail name='李四' detail='我吃了一个煎饼。'/>
      </div>
    );
}
ReactDOM.render(
    <Block/>,
    document.getElementById('root')
)

代码运行效果图:

代码说明: 

第一次调用Detail(article)时

article === {name='张三',detail='我吃了一个苹果'} ,

第二次

调用Detail(article)时

article === {name='李四',detail='我吃了一个煎饼'} ;

由此可见,如 <Detail name='张三' detail='我吃了一个苹果。'/>  这样,其中的name属性,detail属性,其实都会集合在article对象里面,可以根据自己的需要自定义属性。调用的时候传递不同的参数就可以了。

 

3.社交媒体网站上的评论

function formatDate(date) {
  return date.toLocaleDateString();
}

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img
          className="Avatar"
          src={props.author.avatarUrl}
          alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">{props.text}</div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

const comment = {
  date: new Date(),
  text: 'I hope you enjoy learning React!',
  author: {
    name: 'Hello Kitty',
    avatarUrl: 'http://placekitten.com/g/64/64',
  },
};
ReactDOM.render(
  <Comment
    date={comment.date}
    text={comment.text}
    author={comment.author}
  />,
  document.getElementById('root')
);

代码运行效果图:

这个示例代码虽然没有镶入自定义的组件,但是在数据引用上清晰明了,当然可以把里面的样式拆分成更小的自定义组件然后镶入调用,调用方法同示例2。

 

总结:

以上有3个示例,主要是学习组件的创建,使用,箱套,结合数据。可以复制下来在 这里  的html使用,可以直接看到运行效果。

2019-04-21 23:00:55 weixin_44702125 阅读数 87
  • react hooks全套教程

    这个课程主要教大家掌握react hooks的知识点以及它的基本用法,相信听说过react hooks的同学应该都知道它的意义是非常大的。 react hooks可以让我们在函数组件中使用state和生命周期,意味着我们可以不再需要臃肿的class组件了,react hooks的开发体验非常高,效率也非常高,性能也比class组件出色。 还有一点就是你可以基于react hooks封装自己的状态管理器,而不再需要redux、dva、mobx这些第三方状态管理器了。 总的来说,react hooks是非常值得学习,它能让你在开发时事半功倍。

    351 人正在学习 去看看 梁富城

创建组件
方式一:全局创建组件 注意:组件名称:首字母必须大写
function HelloWorld(props){
//必须return 合法的jsx 元素
//return null;
//注意:props 只读
return

组件方式一:全局创建 HelloWorld{ props.name}
;
}
**方式二:**使用class 继承
入门案例:
1.安装:
webpack:
cnpm install webpack webpack-cli -D
webpack-dev-server:
cnpm i webpack-dev-server -D
babel:
cnpm i babel-loader -D
cnpm i @babel/core @babel/plugin-transform-runtime @babel/preset-env -D
cnpm install @babel/runtime @babel/runtime-corejs2 -S
cnpm i @babel/preset-react -D
cnpm i @babel/plugin-proposal-class-properties -D
cnpm i babel-plugin-transform-class-properties -D
React:
cnpm i react react-dom -S
html:
cnpm install html-webpack-plugin -D
CSS:
cnpm install style-loader css-loader -d
2.配置文件
package.json
{
“name”: “day02”,
“version”: “1.0.0”,
“description”: “”,
“main”: “webpack.config.js”,
“scripts”: {
“test”: “echo “Error: no test specified” && exit 1”,

  • "dev": "webpack-dev-server --open --port 3000 --hot --host 127.0.0.1"
    },
    “keywords”: [],
    “author”: “”,
    “license”: “ISC”,
    “devDependencies”: {
    “@babel/core”: “^7.4.3”,
    “@babel/plugin-syntax-class-properties”: “^7.2.0”,
    “@babel/plugin-transform-runtime”: “^7.4.3”,
    “@babel/preset-env”: “^7.4.3”,
    “@babel/preset-react”: “^7.0.0”,
    “babel-loader”: “^8.0.5”,
    “babel-plugin-transform-class-properties”: “^6.24.1”,
    “babel-plugin-transform-property-literals”: “^6.9.4”,
    “css-loader”: “^2.1.1”,
    “html-webpack-plugin”: “^3.2.0”,
    “style-loader”: “^0.23.1”,
    “webpack”: “^4.30.0”,
    “webpack-cli”: “^3.3.0”,
    “webpack-dev-server”: “^3.3.1”
    },
    “dependencies”: {
    “@babel/runtime”: “^7.4.3”,
    “@babel/runtime-corejs2”: “^7.4.3”,
    “react”: “^16.8.6”,
    “react-dom”: “^16.8.6”
    }
    }
    .babelrc
    {
    “presets”: [
    “@babel/preset-env”,"@babel/preset-react"
    ],“plugins”: [
    “@babel/plugin-transform-runtime”,
    “@babel/plugin-syntax-class-properties”,
    “transform-class-properties”
    ]
    }
    webpack.config.js
    const path=require(‘path’)
    //把html映射的项目跟目录
    const HtmlWebPackPlugin=require(‘html-webpack-plugin’)
    //

//创建插件实例
const htmlPlugin=new HtmlWebPackPlugin({
template:path.join(__dirname,’./src/index.html’),//源文件
plugins:‘index.html’//映射的目录,默认项目跟目录

})
//向外暴露一个配置对象
module.exports={
mode:‘development’,//development ,production
plugins:[//第三方插件
htmlPlugin
],module:{//第三方模块匹配规则
rules:[
{
test:/.js|jsxKaTeX parse error: Expected 'EOF', got '}' at position 71: …de_modules/ }̲,{ test:/\.…/,//匹配规则
use:[‘style-loader’,‘css-loader?modules’]//指定解析器 //?modules css启用模块化,防止样式冲突
}
]
},resolve:{//省略后缀名,不配置,默认只能 省略.js 和.json
extensions: [’.js’, ‘.jsx’, ‘.json’],
alias:{//取别名
‘@’:path.join(__dirname,’./src’) //表示把src目录,可以使用@替代
}
}
}
3.代码:
index.html
<html>
<head>
</head>
<body>
<div id=“app”>
</body>
</html>
index.js
//导入组件:生成虚拟DOM对象,生命周期
import React from ‘react’
//导入组件:把创建好的组件和虚拟DOM对象,渲染到页面
import ReactDOM from ‘react-dom’

//导入外部组件 注意默认情况下,后缀名称,不能省略
//使用 @ 符号替代 src 目录,需要配置 webpack.config.js文件,取别名
import CmtList from ‘@/components/CmtList’
ReactDOM.render(<div>
组件
{
//使用组件,方式一:把组件名称当作标签使用
}
<CmtList></CmtList>
</div>,document.getElementById(‘app’))
CmtList.jsx
//导入组件:生成虚拟DOM对象,生命周期
import React from ‘react’
//导入列表项
import CmtIteml from ‘@/components/CmtIteml’
//导入css样式 整个项目生效,这要组件多了,会导致样式冲突
//通过配置文件webpack.config.js开启css 模块化
//开启模块化后,会为每一个样式生成一个唯一的字符串
import cmtcss from ‘@/css/cmtlist.css’
//开启模块后 cmtcss 就有值了,使用样式是,通过这对象,获取生成的唯一字符串

export default class CmtList extends React.Component{
constructor(){
super()
this.state={
datas:[
{id:1,user:‘aaa’,content:‘哈哈沙发12’},
{id:2,user:‘bbb’,content:‘哈哈沙发df’},
{id:3,user:‘ccc’,content:‘哈哈沙发sd’},
]
}
}
render(){
return <div >
<h1 className={cmtcss.title}>评论人列表</h1>
{this.state.datas.map(item=><CmtIteml key={item.id} {…item}>)}
</div>;
}
}
CmtIteml.jsx
//导入组件:生成虚拟DOM对象,生命周期
import React from ‘react’
import cmtcss from ‘@/css/cmtlist.css’

export default function CmtIteml(props){
//必须return 合法的jsx 元素
//return null;
//注意:props 只读
return <div className={cmtcss.cmtbox}>
<h1 className={cmtcss.content}>评论人:{props.user}</h1>
<p>评论内容:{props.content}</p>
</div>;
}
cmtlist.css
.title{
font-size:14px;
color:red
}

.content{
font-size:12px;
}

.cmtbox{
border:1px dashed #ccc;
margin:10px;
padding:10px;
box-shadow:0 0 10px #ccc;

}

项目结构:
demo:
.babelrc
package.json
webpack.config.js
|-src
    |-components
        |-CmtIteml.jsx
        |-CmtList.jsx
    |-css
        |-cmtlist.css
    |-index.html
    |-index.js
|-dist
案例下载

2016-05-06 15:38:06 minihoop 阅读数 1656
  • react hooks全套教程

    这个课程主要教大家掌握react hooks的知识点以及它的基本用法,相信听说过react hooks的同学应该都知道它的意义是非常大的。 react hooks可以让我们在函数组件中使用state和生命周期,意味着我们可以不再需要臃肿的class组件了,react hooks的开发体验非常高,效率也非常高,性能也比class组件出色。 还有一点就是你可以基于react hooks封装自己的状态管理器,而不再需要redux、dva、mobx这些第三方状态管理器了。 总的来说,react hooks是非常值得学习,它能让你在开发时事半功倍。

    351 人正在学习 去看看 梁富城
不可控组件和可控组件
     
 不可控组件使用方式:
      
<span style="font-size:18px;"><input type="text" defaultValue="hello world"/>
      React.findDomNode(this.ref.input).value</span>

可控组件使用方式:
      
<input type="text" defaultValue={this.state.text}/>
      var inputText=this.state.text;

组件可控的好处:
  1.              符合React的数据流
  2.        数据存储在state中,便于使用
  3.        便于对数据进行处理
不可控组件实例
 var MyForm=React.createClass({
       handleSubmit:function(event){
           event.preventDefault();
           var helloTo=ReactDOM.findDOMNode(this.refs.helloTo).value;
           alert(helloTo);
       },
        render:function(){
            return <form onSubmit={this.handleSubmit}>
                <input  type="text" ref="helloTo" defaultValue="Hello World"/><br/>
                <button type="submit" >Speak</button>
            </form>
        }
    });

    ReactDOM.render(<MyForm/>,document.getElementById("app"));

可控组件实例:

var MyForm=React.createClass({
       getInitialState:function(){
           return {
               helloTo:"hello world"
           }
       },
        handleSubmit:function(event){
            event.preventDefault();
            alert(this.state.helloTo);
        },
        handleChange:function(event){
            this.setState({helloTo:event.target.value});
        },
        render:function(){
            return <form onSubmit={this.handleSubmit} >
                <input type="text" value={this.state.helloTo} onChange={this.handleChange}/>
                <button type="submit">submit</button>
            </form>
        }

    });
    ReactDOM.render(<MyForm/>,document.getElementById("app"));

复用事件处理函数

事件处理函数的两种复用方式:
 1 bind复用
      
handleChange:function(name,event){}
      onChange={this.handleChange.bind(this,"input1")}

 2 name复用
     
handleChange:function(event){
       var name=event.target.name;
      }
      onChange={this.handleChange}

bind组件复用实例
 var MyForm=React.createClass({
        getInitialState:function(){
            return{
                username:"",
                gender:"man",
                checked:true
            }
        },
        handleChange:function(name,event){
            var newState={};
            newState[name]=name=="checked"?event.target.checked:event.target.value;
            this.setState(newState);
        },
        handleSubmit:function(event){
            event.preventDefault();
            console.log(this.state);
        },
        render:function(){
            return <form onSubmit={this.handleSubmit}>
                <input type="text" onChange={this.handleChange.bind(this,"username")}/><br/>
                <select value={this.state.gender} onChange={this.handleChange.bind(this,"gender")}>
                    <option value="1">男</option>
                    <option value="2">女</option>
                </select><br/>
                <label htmlFor="checkbox">同意用户协议</label>
                <input id="checkbox" type="checkbox"  value="agree" checked={this.state.checked}
                       onChange={this.handleChange.bind(this,"checked")}
                /><br/>
                <button type="submit">submit</button>
            </form>
        }

    });
    ReactDOM.render(<MyForm/>,document.getElementById("app"));

name组件复用实例
     
      var MyForm=React.createClass({
        getInitialState:function(){
            return{
                username:"",
                gender:"man",
                checked:true
            }
        },
        handleChange:function(event){
            var name=event.target.name;
            var newState={};
            newState[name]=name=="checked"?event.target.checked:event.target.value;
            this.setState(newState,null);
        },
        handleSubmit:function(event){
            event.preventDefault();
            console.log(this.state);
        },
        render:function(){
            return <form onSubmit={this.handleSubmit}>
                <input type="text" onChange={this.handleChange} name="username"/><br/>
                <select value={this.state.gender} onChange={this.handleChange} name="gender">
                    <option value="1">男</option>
                    <option value="2">女</option>
                </select><br/>
                <label htmlFor="checkbox">同意用户协议</label>
                <input id="checkbox" type="checkbox"  value="agree" checked={this.state.checked}
                       onChange={this.handleChange} name="checked"
                /><br/>
                <button type="submit">submit</button>
            </form>
        }

    });
    ReactDOM.render(<MyForm/>,document.getElementById("app"));




2017-05-03 10:24:35 baiyu753159 阅读数 2008
  • react hooks全套教程

    这个课程主要教大家掌握react hooks的知识点以及它的基本用法,相信听说过react hooks的同学应该都知道它的意义是非常大的。 react hooks可以让我们在函数组件中使用state和生命周期,意味着我们可以不再需要臃肿的class组件了,react hooks的开发体验非常高,效率也非常高,性能也比class组件出色。 还有一点就是你可以基于react hooks封装自己的状态管理器,而不再需要redux、dva、mobx这些第三方状态管理器了。 总的来说,react hooks是非常值得学习,它能让你在开发时事半功倍。

    351 人正在学习 去看看 梁富城

抽离组件

永远不要害怕将组件拆分成更小的组件。
例如,考虑这个Comment组件:

import React from 'react';
import ReactDOM from 'react-dom';

function formatDate(date) {
    return date.toISOString();
}

function Comment(props) {
    return (
        <div className="Comment">
            <div className="UserInfo">
                <img className="avatar"
                     src={props.author.avatarUrl}
                     alt={props.author.name}
                />
                <div className="UserInfo-name">
                    {props.author.name}
                </div>
            </div>
            <div className="Comment-text">
                {props.text}
            </div>
            <div className="Comment-date">
                {formatDate(props.date)}
            </div>
        </div>
    );
}

ReactDOM.render(
    <Comment author={{
        avatarUrl: 'https://ss0.bdstatic.com/7Ls0a8Sm1A5BphGlnYG/sys/portrait/item/3ae1dc06.jpg',
        name: 'zhangyatao'
    }} text={'我的名字叫张亚涛'} date={new Date()}/>,
    document.getElementById('root')
);

它接受author(作者),text(内容)和date(日期)作为props,用来描述社交媒体网站上的评论。
这个组件可能很难改变,因为所有的嵌套,它也很难重用其中的单个部分。 让我们从中提取几个组件。

首先,我们将提取avatar

function Avatar(props) {
    return (
        <img className="Avatar"
            src={props.user.avatarUrl}
            alt={props.user.name}
        />
    );
}


avatar不需要知道它正在Comment中呈现。 这就是为什么我们给它的prop一个更通用的名称:user而不是author
我们建议从组件自己的角度来命名props,而不是使用它的上下文。

我们现在可以对Comment组件做一点点简化:

function Comment(props) {
    return (
        <div className="Comment">
            <div className="UserInfo">
                <Avatar user={props.author} />
                <div className="UserInfo-name">
                    {props.author.name}
                </div>
            </div>
            <div className="Comment-text">
                {props.text}
            </div>
            <div className="Comment-date">
                {formatDate(props.date)}
            </div>
        </div>
    );
}


接下来,我们将提取一个UserInfo组件,该组件在用户名称旁边呈现一个avatar:

function UserInfo(props) {
    return (
        <div className="UserInfo">
            <avatar uer={props.user} />
            <div className="UserInfo-name">
                {props.user.name}
            </div>
        </div>
    );
}


这使我们可以进一步简化Comment组件:

function Comment(props) {
    return (
       <div className="Comment">
           <UserInfo user={props.author} />
           <div className="Comment-text">
               {props.text}
           </div>
           <div className="Comment-date">
               {formatDate(props.date)}
           </div>
       </div>
    );
}



最终的代码如下:

import React from 'react';
import ReactDOM from 'react-dom';

function formatDate(date) {
    return date.toISOString();
}
function Avatar(props) {
    return (
        <img className="Avatar"
             src={props.user.avatarUrl}
             alt={props.user.name}
        />
    );
}
function UserInfo(props) {
    return (
        <div className="UserInfo">
            <Avatar user={props.user}/>
            <div className="UserInfo-name">
                {props.user.name}
            </div>
        </div>
    );
}
function Comment(props) {
    return (
        <div className="Comment">
            <UserInfo user={props.author}/>
            <div className="Comment-text">
                {props.text}
            </div>
            <div className="Comment-date">
                {formatDate(props.date)}
            </div>
        </div>
    );
}
ReactDOM.render(
    <Comment author={{
        avatarUrl: 'https://ss0.bdstatic.com/7Ls0a8Sm1A5BphGlnYG/sys/portrait/item/3ae1dc06.jpg',
        name: 'zhangyatao'
    }} text={'我的名字叫张亚涛'} date={new Date()}/>,
    document.getElementById('root')
);

让一个个可重用组件在大型应用程序中交付使用的过程中,抽离组件起初可能看起来像又脏又累的活儿。 所以有一个好的经验法则:如果UI的一部分被使用了好几次(按钮,面板,头像),或者内部比较复杂的东西(App,FeedStory,评论),一个可重用的组件对它来说可以达到最大的发挥空间。

React的组件模式

阅读数 1086

React组件分类

阅读数 534

没有更多推荐了,返回首页