react dangerouslySetInnerHTML not re-rendering content - javascript

Here's my setup:
string-file.properties
someKey=This is my <span class="hello">{0}</span> string!
react-file.jsx
import stringAPI from 'string-file';
class MyComponent extends Component {
get content() {
return { __html: stringAPI.someKey(this.props.word) };
}
render() {
return (
<span dangerouslySetInnerHTML={this.content} />
);
}
}
The argument to stringAPI.someKey get substituted for {0} in the string file and then the final html string is returned. My issue is that this.props.word is being updated while MyComponent is not being updated.
I read somewhere that dangerouslySetInnerHTML tells React that it doesn't need to watch the state of the component that the html is rendered in. If that's true, then I still need a way to do what I'm trying to do.

Set the string as state. When receive new props (componentWillReceiveProps) do a setState. This should rerender the component. If that is not working make sure a unique key is set when the string changes. This also forces a rerender

After adding unique key on div it's working fine.

Related

React Native - Modify a prop within the same component

I have simple questions:
Is it possible to modify a prop (not state) within a React Native component (not from parent component)?
Following [1], if I want to modify a prop within the same component, how can I achieve that (or workarounds if answer in [1] is No)?
If I have the following:
//Parent
render(){
return <View><ChildComponent propA={this.state.propA} /></View>
}
triggerChangeInParent(val) {
this.setState({
propA: val
});
}
//Child (ChildComponent)
render() {
return <View><Text>{this.props.propA}</Text></View>
}
triggerChangeInChild(val) {
//To set props.propA here
}
Both parent and child components are allowed to modify "propA". Whoever triggers the latest will have its value taken precedence for modifying "propA" (eg if "triggerChangeInChild" is triggered after "triggerChangeInParent", then "val" from "triggerChangeInChild" will be used for "propA".
My question is, how do we achieve that (what possible solutions/alternatives to solve this problem)? What is the best practice/pattern?
Thanks!
State is mutable and props is immutable, so you can't modify the props within component. Please do it outside the current component. If you're using redux, you can do it in a reducer.
You should modify the propA on parent only, please write a method in parent, then pass it to child via prop. So you can call the method from child, mean that you make the change inside child.
Parent
contractor(props){
super(props)
this.modifyPropsOnParent = this.modifyPropsOnParent.bind(this)
}
modifyPropsOnParent(){
// do your change here
}
render() {
return <Child modifyPropsOnParent={this.modifyPropsOnParent} otherProp={yourProps} />
}
Child can call the parent method by this.props. modifyPropsOnParent()

ReactJS' Higher Order Components error: "Unknown props"

Yesterday, I was reading the React documentation on higher order components and I was trying to use some of the examples that they have. But, for me, it isn't working.
Here is a simple HOC I created just to wrap another component and see how this works. But since the very beginning, it never worked.
import React, { Component } from 'react';
export default function (enhacedComponent) {
class Authenticate extends Component {
constructor(props) {
super(props);
}
render() {
return <enhacedComponent {...this.props} />;
}
}
return Authenticate;
}
It always returns me this error:
Warning: Unknown props `location`, `params`, `route`, `router`, `routeParams`, `routes` on <enhacedComponent> tag. Remove these props from the element.
When I check the HTML elements part in the console, I find that the actual value this HOC returns is <enhacedComponent></enhacedComponent>. So the wrapped component never got out!
So, in the end, the wrapped component never returns. Just a JSX version of what should be the argument of the HOC.
I think that since JSX is just a another syntax and the unique way to pass plain JavaScript is using {}, I tried to do this, to no success:
<{enhancedComponent} {...this.props }/>
I really don't know what to do or what I am doing wrong.
I'm using this HOC reference. I'm using Webpack 2 with webpack-dev-server as tools on Windows 10.
React thinks you're trying to pass these props to a DOM element and not a react component, which will give you the unknown props error. React interprets lower camel case as a DOM element, so enhacedComponent should be EnhacedComponent.
More info here:
https://facebook.github.io/react/warnings/unknown-prop.html

How do I do a simple onClick to change a child component's classname with React Redux?

I have React Redux working to change my child component's classname, but I do it via
//Subscribe with our function that sets our state
this.props.store.subscribe( this.onSelectChange );
(where the onSelectChange is a function in my component that changes a property on its state.
According to the redux docs, I should instead be using "a view binding library" like ReactRedux's connect method. But every tutorial is incredibly complex. They're hard to understand and appear to be about 5 times more code than what I need to use right now. Using Redux directly, I have about 6 lines of total code.
How can i simply use the "proper" way to make my child component change its classname?
If really all you need is to update a classname on click, React is perfectly capable of doing this without involving the Redux store.
The whole idea with React is that each component has some state object, and a render function to turn the state into markup. If you want to change your view, you should change the state and let React call render again. Take the following example which toggles the classname of a button (not tested):
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
highlighted: false
}
this.buttonClicked = this.buttonClicked.bind(this);
}
buttonClicked() {
var highlighted = !this.state.highlighted
this.setState({
highlighted: highlighted
})
}
render(){
var classname = this.state.highlighted ? "highlighted-btn" : "normal-btn"
return (
<button onClick={this.buttonClicked} className={classname} />
)
}
}
We trigger render by calling setState, in which we use the state to determine the classname for the button.
solution 1
well, if you change className because you want different style.
I will suggest you can use setState in its childComponent instead.
here is for your reference
solution 2
on the other hand, if you want to use Redux to achieve that.
you probably need to have a reducer first. let's say selectState
and then you need an action. here we name it changeSelectState
now, we can use connect from react-redux on the container component
and pass this method down to that presentational component. that's it.
So, the flow you can do is
add a reducer for storing data
add an action for changing the data
import that data and action via connect into container component
pass them down to presentational component
click and change the value via that action

How do I render a string as children in a React component?

Take a simple component:
function MyComponent({ children }) {
return children;
}
This works:
ReactDOM.render(<MyComponent><span>Hello</span></MyComponent>, document.getElementById('stage'));
but this doesn't (I removed the <span/>):
ReactDOM.render(<MyComponent>Hello</MyComponent>, document.getElementById('stage'));
because React tries to call render on the string:
Uncaught TypeError: inst.render is not a function
On the other hand, this works fine:
ReactDOM.render(<p>Hello</p>, document.getElementById('stage'));
How do I make <MyComponent/> behave like <p/>?
If you're using React 16.2 or higher, you can do this using React fragments:
const MyComponent = ({children}) => <>{children}</>
If your editor doesn't support fragment syntax, this will also work:
const MyComponent = ({children}) =>
<React.Fragment>{children}</React.Fragment>
Keep in mind that you're still creating & returning a component (of type MyComponent) as far as React is concerned - it just doesn't create an additional DOM tag. You'll still see a <MyComponent> tag in the React Debug Tools, and MyComponent's return type is still a React element (React.ReactElement).
Well the difference is <p> is an html element and MyComponent is a React Component.
React components need to render/return either a single component or a single html element.
'Hello' is neither.
You need at least one top-level HTML element. Your component can't really just output a string, that's not how React works.
The simplest solution is to simply make your MyComponent wrap it's output in a span or div.
function MyComponent({ children }) {
return <span>{ children }</span>;
}
Currently, in a component's render, you can only return one node; if
you have, say, a list of divs to return, you must wrap your components
within a div, span or any other component.
source
And what you are returning is not a root node. You are returning a react component that is returning a string where it should be returning an HTML element.
You can either pass your string already wrapped with an HTML element (like you already did in your example) or you can wrap your string in a HTML element inside your "MyComponent" like this
function MyComponent({ children }) {
return <span>{ children }</span>;
}
React can render either React components (classes) or HTML Tags (strings). Any HTML tag is by convention lowercase where a Component is Capitalized. Every React component has to render exactly one Tag (or null). To answer your question: you cannot.
In the example above, you render what's given with the children attribute where this will render the tag inside or a string that is not valid.

How I can render react components without jsx format?

I try to make my "smart" popup component, which can open inside itself some components, but my realization isn't good, because it doesn't work.
I use redux approach for creating popup and action of opening my popup is able to get name of any component for rendering before popup will be open;
But I've some problem, after getting parameter, in our case it's nameOfComponent, I need to choose and render component with name nameOfComponent.
And my question now, how do It can render component from array?
// He's my components
import Login from '../Login/login.js';
import Logout from '../Logout/logout.js';
const popupContent = {
Login : Login,
logout: Logout
};
// My component
class Popup extends Component {
componentDidUpdate () {
// for example
const nameOfComponent = "Login";
this.body = this.setBodyPopup(nameOfComponent);
return true;
}
setBodyPopup(property){
return popupContent[property];
}
render() {
// I want to render some element from popupContent here
<div>
// <this.body /> // it's jsx format
{this.body}
</div>
}
}
I added working example here JSfiddle ReactJS
You dont have to use JSX. If you do, right way to do this is to use factory. You can also render regular HTML in the render method, as well as to use vanilla javascript in your code using curly braces.
Also to get I would recommend mapping and iterating through all your items in array and render them one by one in the render method
see example below:
var Login = React.createClass({
render: function() {
return <div>{this.props.name}, logged in</div>;
}
});
// React with JSX
ReactDOM.render(<Login name="John" />,
document.getElementById('containerJSX'));
// React without JSX
var Login = React.createFactory(Login);
ReactDOM.render(Login({ name: 'Tim' }),
document.getElementById('containerNoJSX'));
As commentators suggest, you might want to specify this.body either in constructor or within the render method itself.
However, if I understand your intention correctly, you could just use this.props.children instead.
E.g.
<Popup><MyInnerComponent></Popup>
and in Popup render method
render() {
<div>
{this.props.children}
</div>
}
React actually allows you to use variables with JSX syntax to instantiate components. You should actually be able to call <this.body /> and have it work; however yours will not because you do not define this.body until the componentDidUpdate method, which means it will be undefined for the first render and break everything. I would suggest using local component state for this instead of this.body and making sure it is defined from the start.
At the very least, instantiate this.body in a constructor to some value:
constructor(props) {
super(props);
this.body = 'Login';
}
You can use <this.body /> to render the component, as long as this.body has an actual value. Perhaps you just need:
render() {
return <div>
{this.body ? <this.body /> : null}
</div>
}
With the example you gave, though, you can just put the contents of your componentDidMount in the constructor instead, because the constructor is invoked before the first render pass.
I think you are looking at something like dangerouslySetInnerHtml.
<div dangerouslySetInnerHTML={this.body} />

Categories

Resources