In Part I we saw how to move from sass to a Styled Component for a simple component. So this tutorial assume that you have already installed the styled component made your first try with it. Now we are going to increase the complexity of our controls in the chat app moving to styled components the messages in the chat window.
Each chat window has an array of messages where each one has the name of the sender, the time and the message like
{
from:'rob'
time:'13:23pm'
message:'hi'
}
After that when the message is sent the array is updated and the component Messages is rendered.
The Controls
messages.js
import React from 'react';
import './messages.scss';
const Messages = ({
messages,
from
}) =>
messages.map((data, index) =>
<div className='message-row' key={index}>
<div className={(from===data.from?' sender':' receiver')}>
<div className='sender-time'>{data.time}</div>
<div className='sender-name'>{data.from +":"}</div>
<div className='sender-message'>{data.message}</div>
</div>
</div>
)
export default Messages
messages.scss
.message-row{
width:100%;
float:left;
.sender-name{
color:#4e7ea8;
word-break: initial;
width:100%;
margin-right:50px;
font:18px/20px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif;
}
.sender-message{
width:100%;
margin-left:10px;
float:left;
font:12px/18px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif;
}
.sender-time{
float: right;
font: 11px/20px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif;
color: grey;
}
}
.receiver{
float:left;
padding:5px 10px 5px 10px;
margin-left:30px;
margin-top:10px;
position: relative;
background: #FFFFFF;
border-radius: .4em;
max-width: 450px;
word-break: break-all;
}
.receiver:after {
content: '';
position: absolute;
left: 0;
top: 50%;
width: 0;
height: 0;
border: 20px solid transparent;
border-right-color: #FFFFFF;
border-left: 0;
border-bottom: 0;
margin-top: -10px;
margin-left: -20px;
}
.sender{
padding:5px 10px 5px 10px;
margin-right:30px;
margin-top:10px;
float:right;
position: relative;
background: #a4e893;
border-radius: .4em;
max-width: 450px;
word-break: break-all;
}
.sender:after {
content: '';
position: absolute;
right: 0;
top: 50%;
width: 0;
height: 0;
border: 20px solid transparent;
border-left-color: #a4e893;
border-right: 0;
border-bottom: 0;
margin-top: -10px;
margin-right: -20px;
}
So as we did it in the Part I, we're going to create styled components, in this case that we have nested divs a good approach is go from bottom to top changing small components first.
First add the Styled components library.
import styled from 'styled-components'
As we see in the messages.js we have three divs: sender name, sender time, and sender message. So we're going to create four styled.div components with the styles.
const MessageRow = styled.div`
width:100%;
float:left;
}`
const SenderName = styled.div`
color:#4e7ea8;
word-break: initial;
width:100%;
margin-right:50px;
font:18px/20px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif;`
const SenderMessage = styled.div`
width:100%;
margin-left:10px;
float:left;
font:12px/18px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif;
`
const SenderTime = styled.div`
float: right;
font: 11px/20px 'Open Sans',"Lucida Grande","Lucida Sans Unicode",Arial,Helvetica,Verdana,sans-serif;
color: grey;
`
Then we can change our code in order to use them and the message render looks like this
messages.map((data, index) =>
<MessageRow key={index}>
<div className={(from===data.from?' sender':' receiver')}>
<SenderTime>{data.time}</SenderTime>
<SenderName>{data.from +":"}</SenderName>
<SenderMessage>{data.message}</SenderMessage>
</div>
</MessageRow>
Until now the steps are similar to PART I, now we need to change the div that with some conditional style to make a difference on the message owner. (see screenshot)
To do this we create the styled.div component and change it on our renderer then send to the control the attribute data as a boolean.
NOTE: If you send a boolean like (true,false) you will see an error like "Warning: Received `false` for a non-boolean attribute .." So you should send a boolean as an integer.
<MessageRow key={index}>
<Message data={from===data.from?1:0}>
<SenderTime>{data.time}</SenderTime>
<SenderName>{data.from +":"}</SenderName>
<SenderMessage>{data.message}</SenderMessage>
</Message>
</MessageRow>
For this you can use passed props , and write a function to use the props as variables inside functions like
background :${ props=>props.data? '#a4e893':'#FFFFFF' }
So the idea is that, we check if the value is the owner or not as a boolean and then you can set the correct style for each css property. So you Message Component should look like.
const Message = styled.div`
position: relative;
padding:5px 10px 5px 10px;
margin-top:10px;
word-break: break-all;
max-width: 450px;
border-radius: .4em;
background :${ props=>props.data? '#a4e893':'#FFFFFF' }
float: ${props=> props.data? 'right':'left'};
margin-left:${props=>props.data?'':'30px'};
margin-right:${props=>props.data?'30px':''};
&::after{
content: '';
position: absolute;
top: 50%;
width: 0;
height: 0;
border: 20px solid transparent;
border-bottom: 0;
margin-top: -10px;
//sender
right: ${props=>props.data? '0':''};
left: ${props=>props.data? '':'0'};
border-right-color: ${props=>!props.data? '#FFFFFF':''};
border-left-color: ${props=>props.data ? '#a4e893':''};
border-right: ${props=>props.data?'0':''};
border-left: ${props=>!props.data?'0':''};
margin-right:${props=>props.data?'-20px':''};
margin-left:${props=>!props.data?'-20px':''};
}
IMHO I'll try to keep simple the functions in the styles in order to understand easy what is doing.
I hope this help you to change your code and make it more comprehensive and simple . Feedback is a simple way to share knowledge and is always welcome :)