How to sync when render a component? - reactjs

i have a problem when i try catch new data went i change something in my content and render it.
import React, { Component } from 'react'
import { withNamespaces } from "react-i18next";
class Untitled extends Component {
constructor(props) {
this.columns = [...content]
}
render() {
const columns = this.columns.map((col) => {
return {
...col,
onCell: (record) => ({
record,
dataIndex: col.dataIndex,
title: col.title,
}),
};
});
return (
<div>
{columns}
</div>
)
}
}
export default Untitled
Here, when i change some values in [...content] i want "const columns" will update this new values and render it in return(). I am sure when [...content] update a new value had update in render(). But "const columns" still keep old value.
P/s: I cannot declare this.columns like this.state { columns: [] } because i don't want change code of old dev. Exactly i want get new value this.props.t("TEST") in this.columns when it toggle language.
Thanks you so much.

You can use this.forceUpdate() to manually trigger a re render
. You can get more explanation here https://reactjs.org/docs/react-component.html#forceupdate

Related

how to open airbnb SingleDatePicker calendar on focus

Am trying to include a airbnb SingleDatePicker in my component as shown below
import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
import { SingleDatePicker } from "react-dates";
export default class ExpenseForm extends React.Component {
constructor(props) {
super(props);
this.state = {
createdAt: moment(),
calendarFocused: false
};
this.onDateChange = this.onDateChange.bind(this);
this.onFocusChange = this.onFocusChange.bind(this);
}
onDateChange(createdAt) {
this.setState(() => ({ createdAt }));
}
onFocusChange({ focused }) {
this.setState(() => ({
focused
}));
}
render() {
return (
<div>
<SingleDatePicker
date={this.state.createdAt}
startDateId="MyDatePicker"
onDateChange={this.onDateChange}
focused={this.state.calendarFocused}
onFocusChange={this.onFocusChange}
id="SDP"
/>
</div>
);
}
}
It shows the current date inside the inside the input box as shown below but when i click on the field nothing happens(Calendar widget not opening).
Am not getting any errors in the console to figure out what is the issue. Could anyone please help me on fixing this issue?
It looks like you are targeting the wrong state key in your onFocusChange function. Try changing the function to this:
onFocusChange({ focused }) {
this.setState({ calendarFocused: focused });
}
Notice I also removed the anonymous function from inside of your setState call. You can remove it from your onDateChange function as well:
onDateChange(createdAt) {
this.setState(({ createdAt }));
}
I also noticed that you're using the startDateId prop that is not available for the SingleDatePicker. Airbnb uses that for the DateRangePicker to determine which input to focus on. There is only one input in the SingleDatePicker, so it does not require that prop. You can remove that prop without any change to your functionality.
1- correct this handler
onFocusChange = ({ focused }) => {
this.setState(() => ({ calendarFocused: focused }));
};
2- import 'react-dates/initialize'; //dependency as of v13.0.0
3-since u r not using webpack
Create a CSS file with the contents of require.resolve('react-dates/lib/css/_datepicker.css') and include it in your html section.
To see this in action, you can check out https://github.com/majapw/react-dates-demo which adds react-dates on top of a simple create-react-app setup.

select tag with hashes.map function

I have a question about the getHashes(), there is a map-function that I want to list the hashes in a tag. The listItems is not defined... why?
Can I get some help with this?
import React, { Component } from 'react';
import axios from 'axios';
class Filter extends Component {
constructor(props) {
super(props);
this.state = {
hash: [
"aSj1T", "CD6oL"
]
}
}
getHashes(){
const hashes = this.state.hash;
const listItems = hashes.map((hashes) => <option>{hashes}</option>);
for (var i = 0; i < hashes.length; i++){
const hashUrl = "https://api/v1/hashes/" + hashes[i];
axios.get(hashUrl)
.then((response) => {
const data = response.data[0];
this.state.hash.push(data.hash);
})
.catch((error) => {
console.log(error);
});
}
}
render() {
return (
<div>
<select name="select"
type="select" value={this.getHashes}>
{listItems}
</select>
</div>
);
}
export default Filter;
I stripped down the code, it is with reux axios and much more on my text editor. But i hope you can run this in your text editor to help. It is not tested. If you just explain it is also cool.
1- this.state.hash.push(data.hash); is not a good idea you are mutating the state not changing it by setState
2- listItems is defined inside the function getHashes but never been added to the state or the component instance so you don't have access to it inside the render function
It is not obvious what you are trying to achieve by setting the value of select to a function

Meteor - how to give tracker autorun a callback

I have a little piece of code that renders data from the database according to the path name. My only problem is that when I try to retrieve that data, using this.state.note._id it returns an error that says it cannot find _id of undefined. How would I access my object that is put into a state? It only gives the error when I try to access the items inside the object such as _id
import React from "react";
import { Tracker } from "meteor/tracker";
import { Notes } from "../methods/methods";
export default class fullSize extends React.Component{
constructor(props){
super(props);
this.state = {
note: [],
document: (<div></div>)
};
}
componentWillMount() {
this.tracker = Tracker.autorun(() => {
Meteor.subscribe('notes');
let note = Notes.find({_id: this.props.match.params.noteId}).fetch()
this.setState({ note: note[0] });
});
}
renderDocument(){
console.log(this.state.note);
return <p>Hi</p>
}
componentWillUnmount() {
this.tracker.stop();
}
render(){
return <div>{this.renderDocument()}</div>
}
}
I know that the reason it is returning undefined is because (correct me if I am wrong) the page is rendering the function before the the tracker could refresh the data. How would I get like some sort of callback when the tracker receives some data it will call the renderDocument function?
You're initializing your note state as an array but then you're setting it to a scalar later. You're also not checking to see if the subscription is ready which means that you end up trying to get the state when it is still empty. The tracker will run anytime a reactive data source inside it changes. This means you don't need a callback, you just add any code you want to run inside the tracker itself.
You also don't need a state variable for the document contents itself, your render function can just return a <div /> until the subscription becomes ready.
Note also that .findOne() is equivalent to .find().fetch()[0] - it returns a single document.
When you're searching on _id you can shorthand your query to .findOne(id) instead of .findOne({_id: id})
import React from "react";
import { Tracker } from "meteor/tracker";
import { Notes } from "../methods/methods";
export default class fullSize extends React.Component{
constructor(props){
super(props);
this.state = {
note: null
};
}
componentWillMount() {
const sub = Meteor.subscribe('notes');
this.tracker = Tracker.autorun(() => {
if (sub.ready) this.setState({ note: Notes.findOne(this.props.match.params.noteId) });
});
}
renderDocument(){
return this.state.note ? <p>Hi</p> : <div />;
}
componentWillUnmount() {
this.tracker.stop();
}
render(){
return <div>{this.renderDocument()}</div>
}
}

React filtering the state without ruining it

Im trying to make a search function that renders the name of the people that is matched in a search text input.
The problem is that I set the state to the items that match the search, and then the initial state is lost so no more searching can be done since the state will be empty. So how do I "fill up" the state each time?
Or maybe there is some other way without actually setting the state that im not aware of.
I tried to fix this with an attempt to reset to initial state when the handleSearch function is called right before the filter but that doesnt work.
import React from 'react';
import Header from './Header';
import peopleData from '../persons.json';
class App extends React.Component {
constructor(){
super();
this.handleSearch = this.handleSearch.bind(this);
this.state = {
people: peopleData
}
}
handleSearch(wordToMatch){
this.setState({ people: peopleData }); //Attempt to reset to initial state
const result = this.state.people.filter(d => {
const regex = new RegExp(wordToMatch, 'gi');
return d.Name.match(regex);
});
this.setState({ people: result })
}
render() {
const list = this.state.people.map((d, i) => <li key={i}>{d.Name}</li>);
return (
<div className="myApp">
<Header
tagline={"testing"}
handleSearch={this.handleSearch}
/>
<ul className="contentBody">
{list}
</ul>
</div>
)
}
}
export default App;
Component with the search input:
import React from 'react';
class Header extends React.Component {
render() {
return (
<header>
<input
type="text"
placeholder={this.props.tagline}
ref={(input) => this.searchInput = input}
onChange={() => this.props.handleSearch(this.searchInput.value)}
>
</input>
</header>
)
}
}
export default Header;
How my data looks like
[
{
"Name": "Adam",
"Born": 1971
},
{
"Name": "Bob",
"Born": 1999
},
etc etc for 20 more names
The setState function won't immediately update the state object. So when you reference this.state.people, it will reference the state prior to the setState call. You can update your code to:
handleSearch(wordToMatch) {
const result = peopleData.filter(d => {
const regex = new RegExp(wordToMatch, 'gi');
return d.Name.match(regex);
});
this.setState({
people: result
})
}
In the handleSearch set the state for the searchString variable. Then in the render method, instead of simply mapping the state, you first filter the people list, and that result is what you map.
Change:
const list = this.state.people.map((d, i) => <li key={i}>{d.Name}</li>);
into this:
const list = this.state.people.filter(d => {
const regex = new RegExp(this.state.searchString, 'gi');
return d.Name.match(regex);
}).map((d, i) => <li key={i}>{d.Name}</li>);
This way, the list in the state is left unaltered, and you filter when rendering.

How to pass props to recursive child component and preserve all props

I've run into an interesting problem. I have a parent component that has an array of objects that gets passed to a child component that is a TreeView, meaning it is recursive. I'm passing a function, and a couple of other props to the child, along with the array of objects that is handled recursively by the child. When logging the props in the render function of the child, on the first render all the props are there, but as the recursive function moves through each object in the array, it 'loses' all the other props that are not being handled recursively.
When the component first renders the props object is: prop1, prop2, arrayOfObjects
As it re-renders as recursion is happening, the props object in the child becomes: arrayOfObjects.
prop1, and prop2 have disappeared.
The end result is that I'm not able to call a function in the parent from the child, so I cannot update the state depending on which node in the tree is clicked. I'm not using redux, because this is a style guide - separate from our production app, that is meant to be for devs only, and simple so if possible I'd like to handle all the state from within the components.
There is one other issue - The array of objects is the folder structure of files in our styleguide, and I need to be able to click on a name in the list, and update the view with the contents of that file. This works fine when the file does not have any children, but when there are child nodes, if I click on the parent, the child is clicked. I've tried e.stopPropagation(), e.preventDefault() etc. but have not had any luck. Thanks in advance.
Parent:
import React, {Component} from 'react'
import StyleGuideStructure from '../../styleguide_structure.json'
import StyleTree from './style_tree'
class StyleGuide extends Component {
constructor(props) {
super(props)
let tree = StyleGuideStructure
this.state = {
tree: tree
}
This is the function I'd like to call from the child
setVisibleSection(nodeTitle) {
this.setState({
section: nodeTitle
})
}
render() {
return(
<TreeNode
className="class-name-here"
setVisibleSection={this.setVisibleSection.bind(this)}
node={this.state.tree}
/>
)
}
}
export default StyleGuide
This is essentially what I have in the child, as a fiddle here:
https://jsfiddle.net/ssorallen/XX8mw/
The only difference is that inside the toggle function, I'm trying to call setVisibleSection in the parent, but no dice.
Here is a photo of the console showing the props when the component initially renders, and then after recursion:
I don't think I really understand your 2nd issue. Could you post a fiddle showing the problem?
I think your first issue is that you need to pass the props down to the children. I tried to transcribe your example to your fiddle. You can see by clicking the nodes, the title switched to the node's name.
https://jsfiddle.net/hbjjq3zj/
/**
* Using React 15.3.0
*
* - 2016-08-12: Update to React 15.3.0, class syntax
* - 2016-02-16: Update to React 0.14.7, ReactDOM, Babel
* - 2015-04-28: Update to React 0.13.6
*/
class TreeNode extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: true,
};
}
toggle = () => {
this.setState({visible: !this.state.visible});
this.props.setVisibleSection(this.props.node.title)
};
render() {
var childNodes;
var classObj;
if (this.props.node.childNodes != null) {
childNodes = this.props.node.childNodes.map((node, index) => {
return <li key={index}><TreeNode {...this.props} node={node} /></li>
});
classObj = {
togglable: true,
"togglable-down": this.state.visible,
"togglable-up": !this.state.visible
};
}
var style;
if (!this.state.visible) {
style = {display: "none"};
}
return (
<div>
<h5 onClick={this.toggle} className={classNames(classObj)}>
{this.props.node.title}
</h5>
<ul style={style}>
{childNodes}
</ul>
</div>
);
}
}
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: true,
};
}
toggle = () => {
this.setState({visible: !this.state.visible});
};
setVisibleSection(nodeTitle) {
this.setState({
title: nodeTitle
})
}
render() {
return (
<div>
Title: {this.state.title}
<TreeNode
node={tree}
setVisibleSection={this.setVisibleSection.bind(this)}
/>
</div>
);
}
}
var tree = {
title: "howdy",
childNodes: [
{title: "bobby"},
{title: "suzie", childNodes: [
{title: "puppy", childNodes: [
{title: "dog house"}
]},
{title: "cherry tree"}
]}
]
};
ReactDOM.render(
<ParentComponent />,
document.getElementById("tree")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Resources