× Maximum update depth exceeded - reactjs

Maximum update depth exceeded. This can happen when a component
repeatedly calls setState inside componentWillUpdate or
componentDidUpdate. React limits the number of nested updates to
prevent infinite loops.
this is bossinfo.js
import React from 'react';
import { NavBar, InputItem, TextareaItem, Button } from 'antd-mobile';
import {connect} from 'react-redux';
import {Redirect} from 'react-router-dom';
import AvatarSelector from '../../component/avatar-selector/avatar-selector';
import {updata} from '../../redux/user.redux';
#connect(
state=>state.user,
{updata}
)
class BossInfo extends React.Component{
constructor(props){
super(props)
this.state={
title:'',
company:'',
money:'',
desc:'',
}
}
onChange(key,v){
this.setState({
[key]:v
})
}
render(){
return (
<div>
{this.props.redirectTo?<Redirect to={this.props.redirectTo}></Redirect>:null}
<NavBar mode="dark">Boss完善信息页面</NavBar>
<AvatarSelector selectAvatar={(imagename)=>{
this.setState({
avatar:imagename
})
}}></AvatarSelector>
<InputItem onChange={(v)=>{this.onChange('title',v)}}>
招聘职位
</InputItem>
<InputItem onChange={(v)=>{this.onChange('company',v)}}>
公司名称
</InputItem>
<InputItem onChange={(v)=>{this.onChange('money',v)}}>
职位薪资
</InputItem>
<TextareaItem
title='职位要求'
rows={3}
autoHeight
onChange={(v)=>{this.onChange('desc',v)}}
>
</TextareaItem>
<Button onClick={()=>this.props.updata(this.state)} type='primary'>保存</Button>
</div>
)
}
}
export default BossInfo;
this is user.redux.js
import axios from "axios";
import { getRedirectPath } from '../util' ;
const AUTH_SUCCESS = 'AUTH_SUCCESS';
const ERROR_MSG = 'ERROR_MSG';
const LOAD_DATA = 'LOAD_DATA';
const initStatus={
redirectTo:'',
msg:'',
user:'',
type:'',
}
//reducer
export function user(state=initStatus,action){
switch(action.type){
case AUTH_SUCCESS:
return {...state,msg:'',redirectTo:getRedirectPath(action.data),...action.data}
case LOAD_DATA:
return {...state,...action.data}
case ERROR_MSG:
return {...state,isAuth:false,msg:action.msg}
default:
return state;
}
}
//action
function authSuccess(data){
return { type:AUTH_SUCCESS, data:data }
}
function errorMsg(msg){
return { type:ERROR_MSG, msg:msg }
}
export function register({user,pwd,repeatpwd,type}){
if(!user || !pwd){
return errorMsg('用户名密码必须输入!')
}
if(pwd!=repeatpwd){
return errorMsg('两次密码输入不一致!')
}
//redux-thunk支持返回函数的写法(这边是异步)
return dispatch =>{
axios.post('/user/register',{user,pwd,type}).then(res=>{
if(res.status==200&&res.data.code==0){
dispatch(authSuccess({user,pwd,type,_id:res.data.data._id}))
}else{
dispatch(errorMsg(res.data.msg))
}
})
}
}
export function login({user,pwd}){
if(!user || !pwd){
return errorMsg('用户名和密码不能为空!')
}
return dispatch =>{
axios.post('/user/login',{user,pwd}).then(res=>{
if(res.status==200 && res.data.code==0){
dispatch(authSuccess(res.data.data))
}else{
dispatch(errorMsg(res.data.msg))
}
})
}
}
export function loadData(userinfo){
return {type:LOAD_DATA,data:userinfo}
}
export function updata(data){
return dispatch=>{
axios.post('/user/updata',data)
.then(res=>{
if(res.status==200 && res.data.code==0){
dispatch(authSuccess(res.data.data))
}else{
dispatch(errorMsg(res.data.msg))
}
})
}
}
Why do you keep reporting this problem?Is this pointing in the wrong direction?Asking for help

The onChange function is executing on each render change the function to arrow function like
onChange=(key,v)=>{
v.stopPropagation();
this.setState({
[key]:v
})
}

Related

reset On Resolve the course to loop in React

I'm trying to reset the Values on change of the Dependency value to the SelectInput. But it course to loop and break the page. Here find the code I have done so far.
How can omit this on my code.
import {
SelectInput,
required
} from 'react-admin';
import data from '../data';
import { withStyles } from '#material-ui/core/styles';
import React, { Component } from 'react';
import { DependentInput } from 'aor-dependent-input';
const initialState = {
way_of_join: data.way_of_join
};
class WayOfJoinSelectInput extends Component {
constructor(props) {
super(props)
this.state = initialState;
}
reset(){
this.setState({initialState});
}
switchSector = (props) => {
if (props !== undefined && Object.keys(props).length > 0) {
var value = props.General_Service.service_sector;
this.reset();
switch (value) {
case 'sleas':
this.state.way_of_join.splice(4, 3)
break;
case 'sltes':
this.state.way_of_join.splice(2, 1)
break;
}
}
};
render() {
return (
<DependentInput resolve={this.switchSector}>
<SelectInput
source="General_Service.way_join"
label="Way of Join"
validate={required()}
// onChange={this.reset()}
choices={this.state.way_of_join}
/>
</DependentInput>
)
}
}
export default withStyles(styles)(WayOfJoinSelectInput);
Here find what getting on error.
import {
SelectInput,
required
} from 'react-admin';
import data from '../data';
import { withStyles } from '#material-ui/core/styles';
import React, { Component } from 'react';
import { DependentInput } from 'aor-dependent-input';
const initialState = {
way_of_join: data.way_of_join
};
class WayOfJoinSelectInput extends Component {
constructor(props) {
super(props)
this.state = initialState;
this.reset=this.reset.bind(this);
}
reset(){
this.setState({initialState});
}
switchSector = (props) => {
if (props !== undefined && Object.keys(props).length > 0) {
var value = props.General_Service.service_sector;
this.reset();
switch (value) {
case 'sleas':
this.state.way_of_join.splice(4, 3)
break;
case 'sltes':
this.state.way_of_join.splice(2, 1)
break;
}
}
};
render() {
return (
<DependentInput resolve={this.switchSector}>
<SelectInput
source="General_Service.way_join"
label="Way of Join"
validate={required()}
onChange={this.reset}
choices={this.state.way_of_join}
/>
</DependentInput>
)
}
}
export default withStyles(styles)(WayOfJoinSelectInput);
You need to bind the functions in constructor or use arrow functions.

React redux thunk and component rendering too early before actions

I'm sending request to API and then saving the response to array for later use with thunk, but the problem is that my component is calling render function too fast before my action that saves the response from API to array.
The error that I'm getting is "Consider adding an error boundary to your tree to customize error handling behavior". I set "isFetching" bool state accordingly true/false each action but the render function seems to completely ignore if I put like a condition if isFetching is true then return <p>loading</p> in render. The action thats responsible for setting data from API works and sets properly but then its already too late.
Question is how do I delay rendering the component so by the time it renders I already have the data saved to array and ready to work with?
UPDATE WITH CODE:
Action.js:
import axios from "axios";
export let startFetch = () => {
return {
type: "START_FETCH"
}
}
export let endFetch = (array) => {
return {
type: "END_FETCH",
array
}
}
export let fetchApi = () => {
let url = "http://127.0.0.1:5000/api/stats"
return (dispatch) => {
dispatch(startFetch())
return axios.get(url).then(
(response) => {
dispatch(endFetch(response.data))
},
(err) => {
console.log(err);
}
)
}
}
Reducer.js:
export let fetchApiReducer = (state={isFetching : false, array : []},action) => {
switch(action.type){
case 'START_FETCH':
return {
isFetching : true
}
break;
case 'END_FETCH':
return{
isFetching : false,
array : action.array
}
break;
default:
return state;
}
}
Container.js:
import React, {Component} from "react";
import {connect} from "react-redux";
import {bindActionCreators} from 'redux';
import {fetchApi} from "../actions/adsActions"
class AdsList extends Component {
componentWillMount() {
this.props.fetchApi();
}
renderList(ad) {
return (
<a className="list-group-item list-group-item-action flex-column align-items-start">
<div className="d-flex w-100 justify-content-between">
<h5 className="mb-1">{ad.text}</h5>
<small className="text-muted">{ad.date}</small>
</div>
</a>
);
}
render() {
if(this.props.isFetching == true) {
return (<p>Loading</p>);
} else if (this.props.isFetching == false && this.props.array.length >= 1) {
return (
<div>
{this.props.array.map(this.renderList)}
</div>
);
}
}
}
function mapStateToProps(state) {
return {
isFetching: state.isFetching,
array: state.array
};
}
function matchDispatchToProps(dispatch){
return bindActionCreators({fetchApi: fetchApi}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(AdsList);
Thanks a lot.

trying to pass my arrays (props) into my publish function as selector

import { Mongo } from 'meteor/mongo';
import { Meteor } from 'meteor/meteor';
import React, {Component} from 'react';
import {check} from 'meteor/check';
export const Adressen = new Mongo.Collection('Phonebook');
if (Meteor.isServer) {
Meteor.publish('ArrayToExport', function(branches) {
check(branches, [Match.Any]);
if(branches.length > 10){
return this.ready()
};
return Adressen.find(
{branche: {$in: branches}}, {fields: {firmenname:1, plz:1}}
);
});
}
.
import React, { Component } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import {Adressen} from "../api/MongoDB";
class ExportArray extends Component{
constructor(props){
super(props);
this.state = {
branches: this.props.filteredBranches
};
}
render(){
return(
<div>
<button onClick={this.exportArrays}></button>+
</div>
);
}
}
export default withTracker( (branches) => {
Meteor.subscribe('ArrayToExport', branches);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
this.props.filteredBranche is a pure array,generated through controlled input field. this.props.filteredBranches changes as Input changes, in parent Component.
I thought I was sending my this.props.filteredBranches as an argument through withTracker function. But nothing is passed to the publish function.
if (Meteor.isServer) {
arrayExfct = function (array){
return {
find: {branche:{$in: array }},
fields: {firmenname:1, plz:1}
};
}
Meteor.publish('ArrayToExport', function (array) {
return Adressen.find(
arrayExfct(array).find, arrayExfct(array).fields);
});
}
.
export default withTracker( () => {
arrayExfct = function(array) {
return {
find: {branche: {$in: array}},
fields: {firmenname:1, plz:1}
}
}
var array = ['10555'];
Meteor.subscribe('ArrayToExport', array );
var arrayExfct = Adressen.find(arrayExfct(array).find, arrayExfct(array).fields);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
It would help if you also added an example of where you used this component and how you pass props to it, but I think I see your problem.
You expect the local state in your rendering component to get into the withTracker container, but that would be the other way around. When you make the withTracker container, you are really making another react component that renders your display component (ExportArray) and passes the data (ArrayToExport) down into it.
So, props go like this currently:
external render -> withTracker component -> ExportArray
What you need to do it to get the filteredBranches (which you pass from a parent component?) from the props argument in withTracker and pass that to the subscribtion,
class ExportArray extends Component{
exportArrays () {
const { ArrayToExport } = this.props;
}
render(){
const { ArrayToExport } = this.props;
return(
<div>
<button onClick={this.exportArrays}></button>+
</div>
);
}
}
export default withTracker(propsFromParent => {
const { filteredBranches } = propsFromParent;
Meteor.subscribe('ArrayToExport', filteredBranches);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
Hi the issue is with the code below. The parameter called branches is the props so branches.branches is the array you passed in.
export default withTracker( (branches) => {
Meteor.subscribe('ArrayToExport', branches);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
Try the following.
export default withTracker( ({branches}) => {
Meteor.subscribe('ArrayToExport', branches);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
Notice all that changed was
(branches)
became
({branches})
I solved my problem with a combination of Session Variables and State.
//Client
import React, { Component } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import {Adressen} from "../api/MongoDB";
import {Meteor} from 'meteor/meteor';
import { Session } from 'meteor/session';
class ExportArray extends Component{
constructor(){
super();
this.state = {
x: [],
y: []
};
this.exportArrays = this.exportArrays.bind(this);
}
exportArrays(e){
e.preventDefault();
this.setState({x: this.props.filteredBranches});
this.setState({y: this.props.filteredPostleitzahlen});
}
render(){
var selector = {branche: {$in: this.state.x},plz: {$in: this.state.y}};
Session.set('selector', selector);
return(
<div>
<button onClick={this.exportArrays}> Commit </button>
</div>
);
}
}
export default withTracker( () => {
const ArrayfürExport = Meteor.subscribe('ArrayToExport', Session.get('selector') );
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
//Server
Meteor.publish('ArrayToExport', function (selector) {
console.log('von mongodb', selector);
return Adressen.find(
selector
, {
fields: {firmenname:1, plz:1}
});
});
}

Meteor - return inside of a Tracker.autorun function not returning anything

The function renderNotes() is supposed to return the mapped array which is in a separate file. I noticed that when I return some JSX nothing returns to the screen. I think I know the reason why is because it is returning the info to the tracker function. How would I get the info to return to the renderNotes() function while inside the tracker.autorun() function?
import { Meteor } from "meteor/meteor";
import React from "react";
import { withRouter, Link } from "react-router-dom";
import { Accounts } from "meteor/accounts-base";
import { Tracker } from "meteor/tracker";
import SubjectRoutes from "./subjectRoutes/subjectRoutes";
import { Notes } from "../methods/methods"
import Menu from "./Menu.js";
class Home extends React.Component{
componentWillMount() {
if(!Meteor.userId()){
this.props.history.replace("/login")
}
}
logoutUser(e){
e.preventDefault()
Accounts.logout(() => {
this.props.history.push("/login");
});
}
renderNotes(){
Tracker.autorun(function () {
Meteor.subscribe('notes');
let notes = Notes.find().fetch();
// return notes.map((note) => {
// return <p>{note.imageURL}</p>
// })
return <p>asdas</p> //<--Here
});
}
render(){
return (
<div>
<button onClick={this.logoutUser.bind(this)}>Logout</button>
{this.renderNotes()}
<Menu />
</div>
)
}
}
export default withRouter(Home);
Don't know whether this is a proper answer but I like to usually do something like this
import TrackerReact from 'meteor/ultimatejs:tracker-react';
import { Notes } from "../methods/methods";
export default class Home extends TrackerReact(React.Component) {
constructor(props,) {
super(props);
this.state = {
subscription:{
publishNotes: Meteor.subscribe("publish-Notes")
}
};
}
returnNotes(){
return Notes.find().fetch();
}
render(){
...
const stuff = this.returnNotes().map((note)=>{
return <p>{note}</p>
});
return (
....
{stuff}
)
}
}
This worked for me:
import { Meteor } from "meteor/meteor";
import React from "react";
import { withRouter, Link } from "react-router-dom";
import { Accounts } from "meteor/accounts-base";
import { Tracker } from "meteor/tracker";
import SubjectRoutes from "./subjectRoutes/subjectRoutes";
import { Notes } from "../methods/methods"
import Menu from "./Menu.js";
class Home extends React.Component{
constructor(props){
super(props)
this.state = {
notes: []
}
}
componentWillMount() {
if(!Meteor.userId()){
this.props.history.replace("/login")
}
this.tracker = Tracker.autorun(()=>{
Meteor.subscribe('notes');
let notes = Notes.find().fetch();
this.setState({ notes })
});
}
componentWillUnmount() {
this.tracker.stop();
}
logoutUser(e){
e.preventDefault()
Accounts.logout(() => {
this.props.history.push("/login");
});
}
renderNotes(notes){
return notes.map((note) => {
return (
<div key={note._id}>
<img src={note.imageURL} />
<p>{note.type}</p>
</div>
)
});
}
render(){
return (
<div>
<button onClick={this.logoutUser.bind(this)}>Logout</button>
<Menu />
{this.renderNotes(this.state.notes)}
</div>
)
}
}
export default withRouter(Home);

The reducer does not transmit the initialState

The this.props does not have the loading, error key.
Why?
My code on :
https://github.com/jiexishede/react-redux-demo01
You can fork it and pull request.
Because you don't pass them in your mapStateToProps function
https://github.com/jiexishede/react-redux-demo01/blob/0c1407935cd6c461705d6ca37f3e33484afac327/src/views/Home.js#L8-L10
This should be something like:
#connect(state => {
return {
articleList: state.home.list.articleList,
loading: state.home.list.loading,
error: state.home.list.error,
};
You didn't set up your component to receive updates from your store. Your component won't know that the reducer has updated the state. Check out the code below:
import React, { Component } from 'react';
import * as Redux from 'react-redux'; // Import redux
import Preview from './Preview'
class PreviewList extends Component {
static propTypes = {
loading:React.PropTypes.bool, // 注意 bushi PropTypes.bool, 前面要价 React
error:React.PropTypes.bool,
articleList: React.PropTypes.arrayOf(React.PropTypes.object),
loadArticles: React.PropTypes.func
};
componentDidMount(){
this.props.loadArticles();
}
render(){
const { loading, error, articleList } = this.props;
if(error){
return <p className="message">)0ops, something is wrong. </p>
}
if(loading){
return <p className="message">Loading....</p>
}
// return this.props.articleList.map(item => (
// <Preview {...item} key={item.id}/>
// ))
return (
<div>
{articleList.map(item => {
return <Preview {...item} key={item.id} push={this.props.push} />
})}
</div>
);
}
}
// Connect your component to your store and
// receive updates from your previewList reducer:
export default Redux.connect(state => {
return {
loading: state.previewList.loading,
error: state.previewList.error,
articleList: state.previewList.articleList
};
})(PreviewList);
The problem is that you're not connecting your component to the redux store. You need to install the react-redux package then use it's connect function to connect your component to the store like the following:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Preview from './Preview';
import { loadArticles } from './PreviewListRedux';
class PreviewList extends Component {
static propTypes = {
loading:React.PropTypes.bool,
error:React.PropTypes.bool,
articleList: React.PropTypes.arrayOf(React.PropTypes.object),
loadArticles: React.PropTypes.func
};
componentDidMount(){
this.props.loadArticles();
}
render(){
if (!this.props.loading) {
return <div>Loading...</div>
}
const { loading, error, articleList } = this.props;
if(error){
return <p className="message">)0ops, something is wrong. </p>
}
if(loading){
return <p className="message">Loading....</p>
}
return (
<div>
{articleList.map(item => {
return <Preview {...item} key={item.id} push={this.props.push} />
})}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
loading: state.list.loading,
error: state.list.error,
articleList: state.list.articleList
}
};
export default connect(mapStateToProps, { loadArticles })(PreviewList);
Also, your code needs some major restructuring, it's really difficult to read through it and see how the different pieces are connected together.

Resources