1.脚手架
npm install -g create-react-app
使用方法:create-react-app XXX(项目名称),会自动init并install好项目,直接npm start就好了。
react-scripts 是什么?
react-scripts是create-react-app生成项目所有的依赖。
通常情况下,我们创建spa应用时是使用npm安装项目依赖,在通过配置webpack.config.js进行配置,搭建好环境后在src编写源代码。而create-react-app是自动构建,在package.json中只有react-scripts作为依赖,而在reacr-scripts中已经配置好了项目所有需要的。另外,关于webpack.config.js,需要使用eject命令导出。
引用:https://blog.csdn.net/qq_22889599/article/details/79507721
EnterData(event){ const {textBox} = this.state; if(event.keyCode==13){ this.setState( {textBox:textBox.concat(event.target.value)} ); } }
3.setState与States
this.state={ textBox:[] }
this.setState( {textBox:textBox.concat(event.target.value)} );
但是使用的时候,依然需要:
const {textBox} = this.state;
先取下来再进行数据操作。
4.CSS元素使用
let diagramContainer={ padding: '20px', window.innerWidth, height: window.innerHeight, border: '1px solid gray' };
<div className="Dotcon" style={diagramContainer}>
<div id={pid} style={{position:'absolute',height:'80px','80px',border:'1px solid blue',color:'blue',float:'left',left:pleft,top:ptop}}>{pid}</div>
var name1 ="Mike"; var age1=20; var message1=`hello,${name1},your age is ${age1}`;
6.JS数组CRUD
追加:
textBox.concat(event.target.value)
删除:
var index; const {textBox} = this.state; for(var i=0;i<textBox.length;i++){ if(textBox[i]==value){ index = i; break; } } textBox.splice(index,1);
7.弹框操作(person就是输入的值)
var person=prompt("请输入你的名字","Harry Potter");
8.父子组件传值与回调
首先要将接收方法在父组件传入子组件,子组件的click(或其他事件)事件里再次调用父组件的方法(这个方法已经传入,所以可以从props里拿到,从而回调)。
onChildDelete(value) { //这里拿到的value靠子组件传回 }
return ( <div className="InputComponent"> <AddText onChildDelete={this.onChildDelete.bind(this)} /> </div> ); //注意这里必须.bind(this),否则在onChildDelete方法不可用this.props
onChildDelete(){ this.props.onChildDelete(this.props.Text) } render() { return ( <div className="AddText"> <li>{this.props.Text}<a onClick={this.onChildDelete.bind(this)}></a></li> </div> ); //子组件调用父组件传进来的方法,进行回调,并传回一个值。
引用:https://www.cnblogs.com/lixuemin/p/5754289.html
9.数组Map与事件响应
const BlackComponent = () => <div>我是黑色组件</div>;
class App extends React.Component {
constructor(props) {
super(props);
this.state = { comps: [] };
}
render() {
const { comps } = this.state;
return (
<div>
{comps.map(comp => {
return <BlackComponent key={comp} />;
})}
<p>---------------</p>
<button onClick={() => this.setState({ comps: comps.concat([Date.now()]) })}>加组件</button>
</div>
);
}
}
//当然,map还可以传入index值
10.取Input的值
import React , {Component} from 'react';
export default class App extends Component{
search(){
const inpVal = this.input.value;
console.log(inpVal);
}
render(){
return(
<div>
<input type="text" ref={input => this.input = input} defaultValue="Hello"/>
<button onClick={this.search.bind(this)}></button>
</div>
)
}
}
https://blog.csdn.net/Shuiercc/article/details/81383679
10.安装淘宝镜像
npm install -g cnpm --registry=https://registry.npm.taobao.org
11.react-router的使用
import {BrowserRouter,Route,Switch} from 'react-router-dom'
<BrowserRouter>
<Switch>
<Route exact path='/' render={() => <FirstPage/>} />
<Route path='/RabbitMessageQueue' component={InputComponent}/>
<Route path='/TodoList' component={TodoList}/>
</Switch>
</BrowserRouter>
//需要先注册路由,带exact默认为第一个页面且必须。
在其他组件中:
import {Link} from 'react-router-dom';
<ul>
<li style={{color:color}}><Link style={{color:color}} to='/'>Home</Link></li>
<li style={{color:color}}><Link style={{color:color}} to='/RabbitMessageQueue'>RabbitMessageQueue</Link></li>
<li style={{color:color}}><Link style={{color:color}} to='/TodoList'>TodoList</Link></li>
</ul>
12.redux的使用
在主页面中,注册store,并配置到全局。
import { createStore} from 'redux'
import { Provider } from 'react-redux'
const store = createStore(dataHandler);
function createStore {
switch (action.type) {
case 'CHANGE_THEME':
return {
themeColor: action.color
};
default:
return state;
}
}
render() {
return (
<Provider store={store}>
<BrowserRouter>
...
</BrowserRouter>
</Provider>
);
}
//需要把最外层组件囊括进provider,这样数据才能在所有组件可用。
在子组件中(MenuList):
import { connect } from 'react-redux';
function mapStateToProps(state) {
return {
themeColor: state.themeColor
}
}
function mapDispatchToProps(dispatch) {
return {
setThemeColor: (type,value) => dispatch({
type: type,
color: value
}),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(MenuList)
//mapStateToProps让redux的state同步到react的props中,而mapDispatchToProps同理,将dispatch方法同步到了props中。
然后,你就可以在组件中使用:
const { setThemeColor} = this.props; const color = this.props.themeColor; <button onClick={()=>{setThemeColor('CHANGE_THEME','#3399FF')}}>Normal</button> <li style={{color:color}}><Link style={{color:color}} to='/'>Home</Link></li>
在另外的组件中共享数据也需要这么做。
function mapStateToProps(state) { return { themeColor: state.themeColor } } export default connect(mapStateToProps)(Header) //然后你就可以同步所有组件中的themeColor的变化了,而props数据的改变同样会让render重新绘制。
可以看到,使用redux可以做到跨组件数据同步,而不需要将数据先一步步传递给父组件,再传递给另一个子组件。如果加上@解释器,会更加优雅。
class AutoFocusTextInput extends React.Component { componentDidMount() { this.textInput.focusTextInput(); } render() { return ( <CustomTextInput ref={(input) => { this.textInput = input; }} /> ); } }
14.更改启动端口(VSCode)
{ "scripts": { "start": "set PORT=9000 && roadhog server",//加入set PORT=9000 && }, }
15.react.dva的使用
典型的一个dva应用。
import dva from 'dva'; import React from 'react'; import dva, { connect } from 'dva'; import './style.css'; // 1. Initialize const app = dva(); // 2. Model app.model({ namespace: 'count', state: 0, reducers: { add (count) { return count + 1 }, minus(count) { return count - 1 }, }, }); class TestError extends React.Component { componentDidCatch(e) { alert(e.message); } componentDidMount() { // throw new Error('a'); } render() { return <div>TestError</div> } } // 3. View const App = connect(({ count }) => ({ count }))(function(props) { return ( <div> <TestError /> <h2>{ props.count }</h2> <button key="add" onClick={() => { props.dispatch({type: 'count/add'})}}>+</button> <button key="minus" onClick={() => { props.dispatch({type: 'count/minus'})}}>-</button> </div> ); }); // 4. Router app.router(() => <App />); // 5. Start app.start('#root');
一共需要五步就能搭建一个囊括react、react-router、react-redux的应用。
① const app = dva();
可以往里传入各种初始化数据,hook之类的,比如:
initialState: { products: [ { name: 'dva', id: 1 }, { name: 'antd', id: 2 }, ], },
② app.model();
接收一个json数组,当中三个值:
const modelsCombine=[ { namespace: 'count', state: 0, reducers: { add (count) { return count + 1 }, minus(count) { return count - 1 }, }, }, { namespace: 'products', state: [], reducers: { 'delete'(state, { payload: id }) { return state.filter(item => item.id !== id); }, }, } ] modelsCombine.forEach(m=>app.model(m))
③ const App = connect()();
一般来说,一个页面需要一个model和一个connect()就够了,这里的connect()可以剥离成独立文件,在路由配置中注册好就行,不需要堆在一起。
product.js:
import React from 'react'; import { connect } from 'dva'; import ProductList from '../components/ProductList'; const Products = ({ dispatch, products }) => { function handleDelete(id) { dispatch({ type: 'products/delete', payload: id, }); } return ( <div> <h2>List of Products</h2> <ProductList onDelete={handleDelete} products={products} /> </div> ); }; // export default Products; export default connect(({ products }) => ({ products, }))(Products);
④ app.router();
写一个独立的路由配置就够了。
app.router(require('./router').default); //router.js import React from 'react'; import { Router, Route, Switch } from 'dva/router'; import MainPage from './components/MainPage'; import SecondPage from './components/SecondPage'; import Countor from './routers/Countor'; import Products from './routers/Products'; function RouterConfig({ history }) { return ( <Router history={history}> <Switch> <Route path="/" exact component={MainPage} /> <Route path="/SecondPage" exact component={SecondPage} /> <Route path="/Countor" exact component={Countor} /> <Route path="/Products" exact component={Products} /> </Switch> </Router> ); } export default RouterConfig;
⑤ app.start('#root');
启动。
官方项目分层大致如此:

16.代理
package.json中
"proxy": "http://localhost:8080/"